目录

1、常见图像旋转矫正方法

1.1 基于图像边缘轮廓的旋转矫正

1.2 基于傅里叶变换以及霍夫直线检测的旋转矫正

2、基于Hu距图像旋转矫正

2.1 Hu旋转不变性

2.2 实现步骤

2.2.1 分别计算图像二阶距

2.2.2 利用得到的二阶距计算图像偏转角度

2.2.3 利用仿射变换对图像进行旋转矫正

2.4 程序实现

2.5 旋转矫正效果验证


系统环境 Windows 10 64 位 + OpenCV 3.4.1 64 位

1、常见图像旋转矫正方法

常见的图像旋转矫正方式有:基于图像边缘轮廓的旋转矫正和基于傅里叶变换以及霍夫直线检测的旋转矫正两种方法。

1.1 基于图像边缘轮廓的旋转矫正

1)图像灰度化

2)阈值二值化

3)检测轮廓

4)提取轮廓的包围矩阵(图像前景掩膜)

5)通过提取的包围矩阵获取偏转角度

6)利用仿射变换对图像进行偏转

具体实现参考:OpenCV探索之路(十六):图像矫正技术深入探讨

1.2 基于傅里叶变换以及霍夫直线检测的旋转矫正

1)利用DTF变换计算图像的频谱图

2)频谱中心移动

3)对移动后的频谱图进行二值分割

4)利用霍夫直线检测计算图像倾斜角度

5)利用仿射变换对图像进行旋转矫正

具体实现参考:OpenCV实现基于傅里叶变换的旋转文本校正

傅里叶变换的原理解析参考:傅里叶分析之掐死教程(完整版)和OpenCV图像的傅里叶变换-(补番)

2、基于Hu距图像旋转矫正

除了以上两种方式可以实现图像旋转矫正外,还可以利用HU距旋转不变性对图像进行旋转矫正。

2.1 Hu旋转不变性

图片经过任意角度旋转、任意比例缩放Hu矩都保持不变,即图像Hu 矩的平移、旋转不变性。Hu旋转不变性详情参考:图像不变性特征—hu矩、图像特征_图像矩(Hu矩)。七个不变矩由二阶和三阶中心矩的线性组合构成,具体表达式如下:

在实际应用中,在对图片中物体进行处理时,只有 M1 和 M2 体现良好的不变性,其余的几个不变矩产生的误差比较大。因此,认为只有基于二阶矩的不变矩对二维物体的描述具有良好的旋转、缩放和平移不变性(M1和 M2 由二阶矩组成)。

图像的二阶矩表示图像的主轴,二阶矩值的大小可以确定图像的长轴和短轴,以此来计算轴的方向角度。最后,用主轴相对于法线轴的逆时针旋转角度来近似图像的旋转方向。

2.2 实现步骤

2.2.1 分别计算图像二阶距

其中,I(x,y)表示图像在点(x,y)处的灰度值,

表示图像的质心坐标。

2.2.2 利用得到的二阶距计算图像偏转角度

2.2.3 利用仿射变换对图像进行旋转矫正

2.4 程序实现

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include<iostream>using namespace std;using namespace cv;//计算图像质心坐标
bool calCentroid(Mat srcImg, int width, int height, int *x, int *y)
{if (srcImg.empty()){return false;}int i, j;long long m00 = 0, m10 = 0, m01 = 0;for (i = 0; i < height; i++){for (j = 0; j < width; j++){uchar tmp = srcImg.at<uchar>(i, j);m00 += tmp;m10 += tmp * j;m01 += tmp * i;}}if (m00 != 0){*x = m10 / m00;*y = m01 / m00;//cout <<"x:"<<*x<< endl;//cout << "y:" << *y << endl;}else{*x = 0;*y = 0;return false;}return true;}//计算偏转角度
double getAngle(Mat srcImg)
{double angle = 0;long long  m00 = 0, m11 = 0, m12 = 0, m22 = 0;int Rho11 = 0, Rho12 = 0, Rho22 = 0;int gx = 0, gy = 0;//计算图像偏转角度if (calCentroid(srcImg, srcImg.cols, srcImg.rows, &gx, &gy) == true)//计算图像质心{//cout << "gx:" << gx << endl;//cout << "gy:" << gy << endl;//归一化二阶中心矩for (int i = 0; i < srcImg.rows; i++){for (int j = 0; j < srcImg.cols; j++){uchar tmp = srcImg.at<uchar>(i, j);m00 = m00 + tmp;m12 = m12 + (i - gy)*(j - gx)*tmp;m11 = m11 + (i - gy)*(i - gy)*tmp;m22 = m22 + (j - gx)*(j - gx)*tmp;}}Rho11 = m11 / m00;Rho12 = m12 / m00;Rho22 = m22 / m00;}float tempx = 0, tempy = 0;//计算偏转角度if (Rho11 > Rho22){tempy = Rho11 - Rho22 + sqrt((float)((Rho11 - Rho22)*(Rho11 - Rho22) + 4 * Rho12*Rho12));tempx = (float)(-2 * Rho12);angle = atan(tempy / tempx) * 180 / CV_PI;}else{tempy = (float)(-2 * Rho12);tempx = Rho22 - Rho11 + sqrt((float)((Rho22 - Rho11)*(Rho22 - Rho11) + 4 * Rho12*Rho12));angle = atan(tempy / tempx) * 180 / CV_PI;}//偏转角度范围:-45=< angle <=45if (angle >= -45 && angle <= 45){angle = angle;}else if (angle < -45){angle = -(90 + angle);}else if (angle > 45){angle = 90 - angle;}return angle;
}//对图像进行旋转矫正
bool ContoursCorrection(Mat srcImg, Mat &dstImage)
{if (srcImg.empty()){return false;}Mat gray, binImg;//灰度化cvtColor(srcImg, gray, COLOR_RGB2GRAY);imshow("灰度图", gray);//二值化threshold(gray, binImg, 100, 200, CV_THRESH_BINARY);imshow("二值化", binImg);vector<vector<Point> > contours;vector<Rect> boundRect(contours.size());//注意第5个参数为CV_RETR_EXTERNAL,只检索外框  findContours(binImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //找轮廓cout << contours.size() << endl;for (int i = 0; i < contours.size(); i++){//需要获取的坐标  CvPoint2D32f rectpoint[4];CvBox2D rect = minAreaRect(Mat(contours[i]));cvBoxPoints(rect, rectpoint); //获取4个顶点坐标  //与水平线的角度  int line1 = sqrt((rectpoint[1].y - rectpoint[0].y)*(rectpoint[1].y - rectpoint[0].y) + (rectpoint[1].x - rectpoint[0].x)*(rectpoint[1].x - rectpoint[0].x));int line2 = sqrt((rectpoint[3].y - rectpoint[0].y)*(rectpoint[3].y - rectpoint[0].y) + (rectpoint[3].x - rectpoint[0].x)*(rectpoint[3].x - rectpoint[0].x));//面积太小的直接passif (line1 * line2 < 600){continue;}//新建一个感兴趣的区域图,大小跟原图一样大  Mat RoiSrcImg(srcImg.rows, srcImg.cols, CV_8UC3); //注意这里必须选CV_8UC3RoiSrcImg.setTo(0); //颜色都设置为黑色  //imshow("新建的ROI", RoiSrcImg);//对得到的轮廓填充一下  drawContours(binImg, contours, -1, Scalar(255), CV_FILLED);//抠图到RoiSrcImgsrcImg.copyTo(RoiSrcImg, binImg);计算偏转角度double angle = getAngle(binImg);cout <<"angle:"<<angle<< endl;//为了让正方形横着放,所以旋转角度是不一样的。竖放的,给他加90度,翻过来  if (line1 > line2){angle = 90 + angle;}//再显示一下看看,除了感兴趣的区域,其他部分都是黑色的了  namedWindow("RoiSrcImg", 1);imshow("RoiSrcImg", RoiSrcImg);//对RoiSrcImg进行旋转  Point2f center = rect.center;  //中心点 Mat M2 = getRotationMatrix2D(center, angle, 1);//计算旋转加缩放的变换矩阵 warpAffine(RoiSrcImg, dstImage, M2, RoiSrcImg.size(), 1, 0, Scalar(0));//仿射变换 imshow("旋转之后", dstImage);}return true;}int main(int argc, char *argv[])
{//读取输入图像Mat input = imread("src.png", IMREAD_COLOR);Mat out(input.size(),CV_8UC3,Scalar(0,0,0));ContoursCorrection(input, out);waitKey(0);system("pause");return 0;}

2.5 旋转矫正效果验证

从上图中可以发现,旋转矫正后图像由倾斜转换成为水平。

90度旋转 flip opencv_基于Hu距的图像旋转矫正之OpenCV实现相关推荐

  1. 2.2 获取图像感兴趣区域_基于Hu距的图像旋转矫正之OpenCV实现

    目录 1.常见图像旋转矫正方法 1.1 基于图像边缘轮廓的旋转矫正 1.2 基于傅里叶变换以及霍夫直线检测的旋转矫正 2.基于Hu距图像旋转矫正 2.1 Hu旋转不变性 2.2 实现步骤 2.2.1 ...

  2. createbitmap 旋转90度_解决某些机型调用系统相机照片旋转的问题

    如题,相信很多开发者在调用系统照相机接收拍好的照片时,发现照片被无故旋转了90度.这一问题反映在大部分的三星手机上,当然其他的机器还没试完全,总之是有问题. 于是乎想到如下的解决办法: 识别机型,获取 ...

  3. android 竖屏拍照旋转90度,三星等机型上拍照后图片被旋转90度的解决方案

    考虑到Android7.0以后拍照修改了调用和返回方式,找到了一个看起来还不错的第三方库,实际可能并非如此. -TakePhoto 在三星Note3和S6上测试,发现竖屏拍照后返回的照片是横屏的,在其 ...

  4. 基于NEON指令的图像旋转加速【armv7】

    目录 前言 知识直通车 NEON转置指令 右旋90 4x4矩阵右旋实例 灰度图(单通道)右旋90 彩图(RGB三通道)右旋90 左旋90 4x4矩阵左旋实例 灰度图(单通道)左旋90 彩图(RGB三通 ...

  5. OpenCV_基于Laplacian算子的图像边缘增强

    下面代码实现了基于Laplacian算子的图像边缘增强 . 算法: 边缘增强图像 = 源图像 + 边缘图像 // 基于Laplacian算子的图像边缘增强 // Author: www.icvpr.c ...

  6. android 三星手机拍照旋转90度,解决三星调用系统相机拍照显示图片旋转90度横着的问题...

    /** * 调用系统相机拍照工具类 * @author yao * */ public class CaremaUtil { private static String strImgPath = &q ...

  7. 【毕业设计】基于深度学习的图像超分辨率重建 - opencv python cnn

    文章目录 0 前言 1 什么是图像超分辨率重建 2 应用场景 3 实现方法 4 SRResNet算法原理 5 SRCNN设计思路 6 代码实现 6.1 代码结构组织 6.2 train_srresne ...

  8. 【Android RTMP】NV21 图像旋转处理 ( 图像旋转算法 | 后置摄像头顺时针旋转 90 度 | 前置摄像头顺时针旋转 90 度 )

    文章目录 安卓直播推流专栏博客总结 一. 后置摄像头顺时针旋转 90 度 二. 前置摄像头顺时针旋转 90 度 三. NV21 格式图像旋转代码 安卓直播推流专栏博客总结 Android RTMP 直 ...

  9. 【Android RTMP】NV21 图像旋转处理 ( 问题描述 | 图像顺时针旋转 90 度方案 | YUV 图像旋转细节 | 手机屏幕旋转方向 )

    文章目录 安卓直播推流专栏博客总结 一. NV21 图像格式与 Camera图像传感器方向问题 二. NV21 图像格式视频旋转 1. 图像旋转问题及解决方案 ( 顺时针旋转 90 度 ) 2. NV ...

最新文章

  1. Windbg学习 (0x0012) 命令-批处理命令程序
  2. phpstudy apache配置https
  3. Linux内核实验作业四
  4. 没想到吧,让你一秒变身纸片人的爆火AI特效,背后还有这么多知识点
  5. 【温故知新】CSS学习笔记(背景)
  6. Collatz函数的C++递归实现
  7. 【HDU - 2104】hide handkerchief (素数)
  8. echarts地图api series_echarts学习(4)——地图实现
  9. Linux命令kill和signal
  10. 01 Spring学习之-事件驱动eventListener
  11. 美国Hack the Army 3.0 漏洞奖励计划启动
  12. 详解云安全攻防模型,这些攻击战略和战术越早知道越好!
  13. VS2008(C#)制作网页Tab标签切换方法(四)
  14. python 数据呈现_新手小白初学Python数据可视化 清晰呈现数据变化
  15. 家庭农场海边作弊工具的Andr​​oid的ios
  16. wps文档服务器授权怎么解,如何解决WPS提示授权已到期的问题
  17. 光缆弹性模量计算_光缆的基本常识
  18. mysql 查询优化实验报告_数据库优化查询实验报告.docx
  19. 微型计算机的什么接口主要作为打印机接口,微机接口技术及应用_习题集(含答案)...
  20. 姜烧猪肉+日式厚蛋烧+蚝油青笋

热门文章

  1. NumPy学习(索引和切片,合并,分割,copy与deep copy)
  2. 参数化登陆防止SQL注入攻击
  3. Linux下文件内容查阅命令
  4. [cocos2dx-lua]Hello Lua分析
  5. yii直接执行sql
  6. 【semantic】如何理解 web 语义化?
  7. android在activity中锁屏解锁后重走OnCreate的问题的解决办法
  8. opencv 阈值分割_用 OpenCV 去除图片中的水印,骚操作!
  9. php5.4漏洞解决,php5.4.3的远程代码执行漏洞,提权挺管用
  10. 怎么删除python3.7注册表内容_python3操作注册表的方法(Url protocol)