opencv实现图像倾斜校正

 更新时间:2022年07月30日 16:50:54   作者:无左无右  
这篇文章主要为大家详细介绍了opencv实现图像倾斜校正,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了opencv实现图像倾斜校正的具体代码,供大家参考,具体内容如下

今天的任务是如图这两种情况,我现在的情况是和如图一样的,左图左边倾斜一点儿,那么我需要把左边压低倾斜校正。右图,右边倾斜我需要把右边下压到水平位置倾斜校正。我的场景不会有大角度的倾斜,就这么点可能的不会超过45°的小角度。
标准的传统图像处理方法。首先就是灰度,二值化,取轮廓,筛选得到目标(面积最大的那个),得到倾斜角度,转正。
具体过程就不详细说了,都在代码里面一看就懂。效果图如下:

#include <iostream>
#include"opencv2/opencv.hpp"
using namespace std;
using namespace cv;


bool cmp_x(cv::Point pt1, cv::Point pt2)
{
    return (pt1.x < pt2.x);
}

cv::Point2f get_mid_pt(cv::Point2f pt1, cv::Point2f pt2)
{
    return cv::Point2f((pt1.x + pt2.x)/2.0,(pt1.y + pt2.y) / 2.0);
}

double get_point_angle(cv::Point2f pointO,cv::Point2f pointA)
{
    double angle = 0;
    cv::Point2f point;
    double temp;
    point = cv::Point2f((pointA.x - pointO.x), (pointA.y - pointO.y));

    if ((0==point.x) && (0==point.y))
    {
        return 0;
    }

    if (0==point.x)
    {
        angle = 90;
        return angle;
    }

    if (0==point.y)
    {
        angle = 0;
        return angle;
    }

    temp = fabsf(float(point.y)/float(point.x));
    temp = atan(temp);
    temp = temp*180/CV_PI ;

    if ((0<point.x)&&(0<point.y))
    {
        angle = 360 - temp;
        return angle;
    }

    if ((0>point.x)&&(0<point.y))
    {
        angle = 360 - (180 - temp);
        return angle;
    }

    if ((0<point.x)&&(0>point.y))
    {
        angle = temp;
        return angle;
    }

    if ((0>point.x)&&(0>point.y))
    {
        angle = 180 - temp;
        return angle;
    }

    printf("sceneDrawing :: getAngle error!");
    return -1;
}

int RotateImage(const cv::Mat &src, double angle, cv::Mat &dst, cv::Mat &rot_matrix, bool crop = true, int flags = cv::INTER_NEAREST,
                int borderMode = cv::BORDER_CONSTANT, const cv::Scalar &borderValue = cv::Scalar())
{
    if(0 == src.cols * src.rows) { return 0;}
    cv::Point2f center(src.cols / 2.0f, src.rows / 2.0f);
    rot_matrix = cv::getRotationMatrix2D(center, angle, 1.0);
    if (crop) {
        if (dst.data == NULL) {
            dst = cv::Mat(src.rows, src.cols, src.type());
        }
    } else {
        cv::Rect bbox = cv::RotatedRect(center, cv::Size2f(src.cols, src.rows), angle).boundingRect();
        double *p = (double *) rot_matrix.data;
        p[2] += bbox.width / 2.0 - center.x;
        p[5] += bbox.height / 2.0 - center.y;
        if (dst.rows != bbox.height || dst.cols != bbox.width) {
            dst = cv::Mat(bbox.height, bbox.width, src.type());
        }
    }
    cv::warpAffine(src, dst, rot_matrix, dst.size(), flags, borderMode, borderValue);
    return 0;
}


int main(int argc, char *argv[])
{
    cv::Mat img = cv::imread("/data_1/everyday/0325/13.jpeg");

    cv::Mat m_gray,m_bi;
    cv::cvtColor(img,m_gray,CV_BGR2GRAY);
    cv::threshold(m_gray,m_bi,100,255,THRESH_BINARY_INV);

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(m_bi,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());

    RotatedRect rt_rot_max,rt_tmp;
    int max_szie = -1;
    for(int i=0;i<contours.size();i++)
    {
        rt_tmp = minAreaRect(Mat(contours[i]));
        if(rt_tmp.size.area() > max_szie)
        {
            max_szie = rt_tmp.size.area();
            rt_rot_max = rt_tmp;
        }
    }
    std::vector<cv::Point2f> v_pt(4);
    rt_rot_max.points(v_pt.data());

    std::sort(v_pt.begin(),v_pt.end(),cmp_x);

    cv::Point2f pt_left = get_mid_pt(v_pt[0], v_pt[1]);
    cv::Point2f pt_right = get_mid_pt(v_pt[2], v_pt[3]);

    double ang = get_point_angle(pt_left,pt_right);
    std::cout<<"ang="<<ang<<std::endl;

    cv::circle(img,v_pt[0],6,Scalar(50,12,189),3);
    cv::circle(img,v_pt[1],6,Scalar(10,255,255),3);
    cv::circle(img,v_pt[2],6,Scalar(150,120,19),3);
    cv::circle(img,v_pt[3],6,Scalar(0,0,0),3);

    cv::Mat m_rot,rot_matrix;
    RotateImage(img, -ang, m_rot, rot_matrix, false);

    cv::imshow("m_rot",m_rot);
    cv::imshow("m_bi",m_bi);
    cv::imshow("m_gray",m_gray);
    cv::imshow("img",img);
    cv::waitKey(0);

    return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • C语言中的自定义类型之结构体与枚举和联合详解

    C语言中的自定义类型之结构体与枚举和联合详解

    今天我们来学习一下自定义类型,自定义类型包括结构体、枚举、联合体,小编觉得挺不错的,现在就分享给大家,也给大家做个参考
    2022-06-06
  • Visual Studio中的解决方案中不显示项目分析

    Visual Studio中的解决方案中不显示项目分析

    这篇文章主要为大家介绍了Visual Studio中的解决方案中不显示项目问题分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • C++ 分割字符串数据的实现方法

    C++ 分割字符串数据的实现方法

    这篇文章主要介绍了C++ 分割字符串数据的实现方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09
  • 基于memset()函数的深入理解

    基于memset()函数的深入理解

    本篇文章是对memset()函数又进行了深一步的了解,需要的朋友参考下
    2013-05-05
  • 利用C语言结构体实现通讯录

    利用C语言结构体实现通讯录

    这篇文章主要为大家详细介绍了利用C语言结构体实现通讯录,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • Linux C 时间函数应用

    Linux C 时间函数应用

    本文是关于Linux C时间函数 time_t struct tm 进行了详细的分析介绍并有应用实例,希望能帮到有需要的同学
    2016-07-07
  • C语言进阶输入输出重定向与fopen函数使用示例详解

    C语言进阶输入输出重定向与fopen函数使用示例详解

    这篇文章主要为大家介绍了C语言进阶输入输出重定向与fopen函数的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-02-02
  • C语言 指针与二维数组详解

    C语言 指针与二维数组详解

    本文主要介绍C语言 指针与二维数组,这里整理了详细的资料及示例代码,有需要的小伙伴可以参考下
    2016-08-08
  • C语言实现简单猜拳小游戏

    C语言实现简单猜拳小游戏

    这篇文章主要为大家详细介绍了C语言实现简单猜拳小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • C++连接mysql数据库并读取数据的具体步骤

    C++连接mysql数据库并读取数据的具体步骤

    在实际开发中我们经常需要对数据库进行访问,针对不同类型的数据库(如MySQL、sqLite、Access、Excel等),如果采用不同的方法进行连接,会把我们搞崩溃,下面这篇文章主要给大家介绍了关于C++连接mysql数据库并读取数据的具体步骤,需要的朋友可以参考下
    2023-04-04

最新评论