wordpress外贸建站主题,济宁 做网站,明星网站开发项目介绍,长春企业模板建站OpenCV图片校正 背景几种校正方法1.傅里叶变换 霍夫变换 直线 角度 旋转3.四点透视 角度 旋转4.检测矩形轮廓 角度 旋转参考 背景
遇到偏的图片想要校正成水平或者垂直的。
几种校正方法
对于倾斜的图片通过矫正可以得到水平的图片。一般有如下几种基于opencv的组合方… OpenCV图片校正 背景几种校正方法1.傅里叶变换 霍夫变换 直线 角度 旋转3.四点透视 角度 旋转4.检测矩形轮廓 角度 旋转参考 背景
遇到偏的图片想要校正成水平或者垂直的。
几种校正方法
对于倾斜的图片通过矫正可以得到水平的图片。一般有如下几种基于opencv的组合方式进行图片矫正。
1、傅里叶变换 霍夫变换 直线 角度 旋转2、边缘检测 霍夫变换 直线角度 旋转3、四点透视 角度 旋转4、检测矩形轮廓 角度 旋转
1.傅里叶变换 霍夫变换 直线 角度 旋转
#include opencv2/core/core.hpp
#include opencv2/imgproc/imgproc.hpp
#include opencv2/highgui/highgui.hpp
#include iostreamusing namespace cv;
using namespace std;// 二值化阈值
#define GRAY_THRESH 150// 直线上点的个数
#define HOUGH_VOTE 50int main(int argc, char **argv)
{//Read a single-channel imageconst char* filename 31.png;Mat srcImg imread(filename, CV_LOAD_IMAGE_GRAYSCALE);if (srcImg.empty())return -1;imshow(source, srcImg);Point center(srcImg.cols / 2, srcImg.rows / 2);//Expand image to an optimal size, for faster processing speed//Set widths of borders in four directions//If borderTypeBORDER_CONSTANT, fill the borders with (0,0,0)Mat padded;int opWidth getOptimalDFTSize(srcImg.rows);int opHeight getOptimalDFTSize(srcImg.cols);copyMakeBorder(srcImg, padded, 0, opWidth - srcImg.rows, 0, opHeight - srcImg.cols, BORDER_CONSTANT, Scalar::all(0));Mat planes[] { Mat_float(padded), Mat::zeros(padded.size(), CV_32F) };Mat comImg;//Merge into a double-channel imagemerge(planes, 2, comImg);//Use the same image as input and output,//so that the results can fit in Mat welldft(comImg, comImg);//Compute the magnitude//planes[0]Re(DFT(I)), planes[1]Im(DFT(I))//magnitudesqrt(Re^2Im^2)split(comImg, planes);magnitude(planes[0], planes[1], planes[0]);//Switch to logarithmic scale, for better visual results//M2log(1M1)Mat magMat planes[0];magMat Scalar::all(1);log(magMat, magMat);//Crop the spectrum//Width and height of magMat should be even, so that they can be divided by 2//-2 is 11111110 in binary system, operator make sure width and height are always evenmagMat magMat(Rect(0, 0, magMat.cols -2, magMat.rows -2));//Rearrange the quadrants of Fourier image,//so that the origin is at the center of image,//and move the high frequency to the cornersint cx magMat.cols / 2;int cy magMat.rows / 2;Mat q0(magMat, Rect(0, 0, cx, cy));Mat q1(magMat, Rect(0, cy, cx, cy));Mat q2(magMat, Rect(cx, cy, cx, cy));Mat q3(magMat, Rect(cx, 0, cx, cy));Mat tmp;q0.copyTo(tmp);q2.copyTo(q0);tmp.copyTo(q2);q1.copyTo(tmp);q3.copyTo(q1);tmp.copyTo(q3);//Normalize the magnitude to [0,1], then to[0,255]normalize(magMat, magMat, 0, 1, CV_MINMAX);Mat magImg(magMat.size(), CV_8UC1);magMat.convertTo(magImg, CV_8UC1, 255, 0);imshow(magnitude, magImg);//imwrite(imageText_mag.jpg,magImg);//Turn into binary imagethreshold(magImg, magImg, GRAY_THRESH, 255, CV_THRESH_BINARY);imshow(mag_binary, magImg);//imwrite(imageText_bin.jpg,magImg);//Find lines with Hough TransformationvectorVec2f lines;float pi180 (float)CV_PI / 180;Mat linImg(magImg.size(), CV_8UC3);HoughLines(magImg, lines, 1, pi180, HOUGH_VOTE, 0, 0);int numLines lines.size();for (int l 0; lnumLines; l){float rho lines[l][0], theta lines[l][1];Point pt1, pt2;double a cos(theta), b sin(theta);double x0 a*rho, y0 b*rho;pt1.x cvRound(x0 1000 * (-b));pt1.y cvRound(y0 1000 * (a));pt2.x cvRound(x0 - 1000 * (-b));pt2.y cvRound(y0 - 1000 * (a));line(linImg, pt1, pt2, Scalar(255, 0, 0), 3, 8, 0);}imshow(lines, linImg);//imwrite(imageText_line.jpg,linImg);if (lines.size() 3){cout found three angels: endl;cout lines[0][1] * 180 / CV_PI endl lines[1][1] * 180 / CV_PI endl lines[2][1] * 180 / CV_PI endl endl;}//Find the proper angel from the three found angelsfloat angel 0;float piThresh (float)CV_PI / 90;float pi2 CV_PI / 2;for (int l 0; lnumLines; l){float theta lines[l][1];if (abs(theta) piThresh || abs(theta - pi2) piThresh)continue;else{angel theta;break;}}//Calculate the rotation angel//The image has to be square,//so that the rotation angel can be calculate rightangel angelpi2 ? angel : angel - CV_PI;if (angel ! pi2){float angelT srcImg.rows*tan(angel) / srcImg.cols;angel atan(angelT);}float angelD angel * 180 / (float)CV_PI;cout the rotation angel to be applied: endl angelD endl endl;//Rotate the image to recoverMat rotMat getRotationMatrix2D(center, angelD, 1.0);Mat dstImg Mat::ones(srcImg.size(), CV_8UC3);warpAffine(srcImg, dstImg, rotMat, srcImg.size(), 1, 0, Scalar(255, 255, 255));imshow(result, dstImg);//imwrite(imageText_D.jpg,dstImg);waitKey(0);return 0;
}opencv4x
#include opencv2/core/core.hpp
#include opencv2/imgproc/imgproc.hpp
#include opencv2/highgui/highgui.hpp
#include opencv2/imgcodecs/legacy/constants_c.h
#include iostreamusing namespace cv;
using namespace std;// 二值化阈值
#define GRAY_THRESH 150// 直线上点的个数
#define HOUGH_VOTE 50int main(int argc, char **argv)
{//Read a single-channel imageconst char* filename argv[1];Mat srcImg imread(filename, CV_LOAD_IMAGE_GRAYSCALE);if (srcImg.empty())return -1;imshow(source, srcImg);Point center(srcImg.cols / 2, srcImg.rows / 2);//Expand image to an optimal size, for faster processing speed//Set widths of borders in four directions//If borderTypeBORDER_CONSTANT, fill the borders with (0,0,0)Mat padded;int opWidth getOptimalDFTSize(srcImg.rows);int opHeight getOptimalDFTSize(srcImg.cols);copyMakeBorder(srcImg, padded, 0, opWidth - srcImg.rows, 0, opHeight - srcImg.cols, BORDER_CONSTANT, Scalar::all(0));Mat planes[] { Mat_float(padded), Mat::zeros(padded.size(), CV_32F) };Mat comImg;//Merge into a double-channel imagemerge(planes, 2, comImg);//Use the same image as input and output,//so that the results can fit in Mat welldft(comImg, comImg);//Compute the magnitude//planes[0]Re(DFT(I)), planes[1]Im(DFT(I))//magnitudesqrt(Re^2Im^2)split(comImg, planes);magnitude(planes[0], planes[1], planes[0]);//Switch to logarithmic scale, for better visual results//M2log(1M1)Mat magMat planes[0];magMat Scalar::all(1);log(magMat, magMat);//Crop the spectrum//Width and height of magMat should be even, so that they can be divided by 2//-2 is 11111110 in binary system, operator make sure width and height are always evenmagMat magMat(Rect(0, 0, magMat.cols -2, magMat.rows -2));//Rearrange the quadrants of Fourier image,//so that the origin is at the center of image,//and move the high frequency to the cornersint cx magMat.cols / 2;int cy magMat.rows / 2;Mat q0(magMat, Rect(0, 0, cx, cy));Mat q1(magMat, Rect(0, cy, cx, cy));Mat q2(magMat, Rect(cx, cy, cx, cy));Mat q3(magMat, Rect(cx, 0, cx, cy));Mat tmp;q0.copyTo(tmp);q2.copyTo(q0);tmp.copyTo(q2);q1.copyTo(tmp);q3.copyTo(q1);tmp.copyTo(q3);//Normalize the magnitude to [0,1], then to[0,255]//normalize(magMat, magMat, 0, 1, CV_MINMAX);normalize(magMat, magMat, 0, 1, NORM_MINMAX);Mat magImg(magMat.size(), CV_8UC1);magMat.convertTo(magImg, CV_8UC1, 255, 0);imshow(magnitude, magImg);//imwrite(imageText_mag.jpg,magImg);//Turn into binary imagethreshold(magImg, magImg, GRAY_THRESH, 255, cv::THRESH_BINARY);imshow(mag_binary, magImg);//imwrite(imageText_bin.jpg,magImg);//Find lines with Hough TransformationvectorVec2f lines;float pi180 (float)CV_PI / 180;Mat linImg(magImg.size(), CV_8UC3);HoughLines(magImg, lines, 1, pi180, HOUGH_VOTE, 0, 0);int numLines lines.size();for (int l 0; lnumLines; l){float rho lines[l][0], theta lines[l][1];Point pt1, pt2;double a cos(theta), b sin(theta);double x0 a*rho, y0 b*rho;pt1.x cvRound(x0 1000 * (-b));pt1.y cvRound(y0 1000 * (a));pt2.x cvRound(x0 - 1000 * (-b));pt2.y cvRound(y0 - 1000 * (a));line(linImg, pt1, pt2, Scalar(255, 0, 0), 3, 8, 0);}imshow(lines, linImg);//imwrite(imageText_line.jpg,linImg);if (lines.size() 3){cout found three angels: endl;cout lines[0][1] * 180 / CV_PI endl lines[1][1] * 180 / CV_PI endl lines[2][1] * 180 / CV_PI endl endl;}//Find the proper angel from the three found angelsfloat angel 0;float piThresh (float)CV_PI / 90;float pi2 CV_PI / 2;for (int l 0; lnumLines; l){float theta lines[l][1];if (abs(theta) piThresh || abs(theta - pi2) piThresh)continue;else{angel theta;break;}}//Calculate the rotation angel//The image has to be square,//so that the rotation angel can be calculate rightangel angelpi2 ? angel : angel - CV_PI;if (angel ! pi2){float angelT srcImg.rows*tan(angel) / srcImg.cols;angel atan(angelT);}//float angelD angel * 180 / (float)CV_PI;float angelD angel * 180 / (float)CV_PI;cout the rotation angel to be applied: angelD endl endl;//Rotate the image to recoverMat rotMat getRotationMatrix2D(center, angelD, 1.0);Mat dstImg Mat::ones(srcImg.size(), CV_8UC3);warpAffine(srcImg, dstImg, rotMat, srcImg.size(), 1, 0, Scalar(255, 255, 255));imshow(result, dstImg);imwrite(imageText_D.jpg,dstImg);waitKey(0);return 0;
}CMakeLists.txt
project( main )
cmake_minimum_required(VERSION 3.10)
#添加头文件路径
include_directories(/usr/local/include /usr/local/include/opencv4 /usr/local/include/opencv4/opencv2)
#添加库文件路径
link_directories(/usr/local/lib)add_executable(main test.cpp)
target_link_libraries( main -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs)3.四点透视 角度 旋转
#include opencv2/imgproc.hpp
#include opencv2/highgui.hpp
#include iostream
using namespace cv;
using namespace std;// 直线上点的个数
#define HOUGH_VOTE 50//度数转换
double DegreeTrans(double theta)
{double res theta / CV_PI * 180;return res;
}//逆时针旋转图像degree角度原尺寸
void rotateImage(Mat src, Mat img_rotate, double degree)
{//旋转中心为图像中心 Point2f center;center.x float(src.cols / 2.0);center.y float(src.rows / 2.0);int length 0;length sqrt(src.cols*src.cols src.rows*src.rows);//计算二维旋转的仿射变换矩阵 Mat M getRotationMatrix2D(center, degree, 1);warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射变换背景色填充为白色
}//通过霍夫变换计算角度
double CalcDegree(const Mat srcImage, Mat dst)
{Mat midImage, dstImage;Canny(srcImage, midImage, 50, 200, 3);cvtColor(midImage, dstImage, CV_GRAY2BGR);//通过霍夫变换检测直线vectorVec2f lines;HoughLines(midImage, lines, 1, CV_PI / 180, HOUGH_VOTE);//第5个参数就是阈值阈值越大检测精度越高//cout lines.size() endl;//由于图像不同阈值不好设定因为阈值设定过高导致无法检测直线阈值过低直线太多速度很慢//所以根据阈值由大到小设置了三个阈值如果经过大量试验后可以固定一个适合的阈值。float sum 0;//依次画出每条线段for (size_t i 0; i lines.size(); i){float rho lines[i][0];float theta lines[i][1];Point pt1, pt2;//cout theta endl;double a cos(theta), b sin(theta);double x0 a*rho, y0 b*rho;pt1.x cvRound(x0 1000 * (-b));pt1.y cvRound(y0 1000 * (a));pt2.x cvRound(x0 - 1000 * (-b));pt2.y cvRound(y0 - 1000 * (a));//只选角度最小的作为旋转角度sum theta;line(dstImage, pt1, pt2, Scalar(55, 100, 195), 1, LINE_AA); //Scalar函数用于调节线段颜色imshow(直线探测效果图, dstImage);}float average sum / lines.size(); //对所有角度求平均这样做旋转效果会更好cout average theta: average endl;double angle DegreeTrans(average) - 90;rotateImage(dstImage, dst, angle);//imshow(直线探测效果图2, dstImage);return angle;
}void ImageRecify(const char* pInFileName, const char* pOutFileName)
{double degree;Mat src imread(pInFileName);imshow(原始图, src);Mat dst;//倾斜角度矫正degree CalcDegree(src, dst);rotateImage(src, dst, degree);cout angle: degree endl;imshow(旋转调整后, dst);Mat resulyImage dst(Rect(0, 0, dst.cols, 500)); //根据先验知识估计好文本的长宽再裁剪下来imshow(裁剪之后, resulyImage);imwrite(recified.jpg, resulyImage);
}int main()
{ImageRecify(31.png, FinalImage.jpg);waitKey();return 0;
}opencv4.x
#include opencv2/imgproc.hpp
#include opencv2/highgui.hpp
#include iostream
using namespace cv;
using namespace std;// 直线上点的个数
#define HOUGH_VOTE 50//度数转换
double DegreeTrans(double theta)
{double res theta / CV_PI * 180;return res;
}//逆时针旋转图像degree角度原尺寸
void rotateImage(Mat src, Mat img_rotate, double degree)
{//旋转中心为图像中心 Point2f center;center.x float(src.cols / 2.0);center.y float(src.rows / 2.0);int length 0;length sqrt(src.cols*src.cols src.rows*src.rows);//计算二维旋转的仿射变换矩阵 Mat M getRotationMatrix2D(center, degree, 1);warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射变换背景色填充为白色
}//通过霍夫变换计算角度
double CalcDegree(const Mat srcImage, Mat dst)
{Mat midImage, dstImage;Canny(srcImage, midImage, 50, 200, 3);cvtColor(midImage, dstImage, COLOR_GRAY2BGR);//通过霍夫变换检测直线vectorVec2f lines;HoughLines(midImage, lines, 1, CV_PI / 180, HOUGH_VOTE);//第5个参数就是阈值阈值越大检测精度越高//cout lines.size() endl;//由于图像不同阈值不好设定因为阈值设定过高导致无法检测直线阈值过低直线太多速度很慢//所以根据阈值由大到小设置了三个阈值如果经过大量试验后可以固定一个适合的阈值。float sum 0;//依次画出每条线段for (size_t i 0; i lines.size(); i){float rho lines[i][0];float theta lines[i][1];Point pt1, pt2;//cout theta endl;double a cos(theta), b sin(theta);double x0 a*rho, y0 b*rho;pt1.x cvRound(x0 1000 * (-b));pt1.y cvRound(y0 1000 * (a));pt2.x cvRound(x0 - 1000 * (-b));pt2.y cvRound(y0 - 1000 * (a));//只选角度最小的作为旋转角度sum theta;line(dstImage, pt1, pt2, Scalar(55, 100, 195), 1, LINE_AA); //Scalar函数用于调节线段颜色imshow(直线探测效果图, dstImage);}float average sum / lines.size(); //对所有角度求平均这样做旋转效果会更好cout average theta: average endl;double angle DegreeTrans(average) - 90;rotateImage(dstImage, dst, angle);//imshow(直线探测效果图2, dstImage);return angle;
}void ImageRecify(const char* pInFileName, const char* pOutFileName)
{double degree;Mat src imread(pInFileName);imshow(原始图, src);Mat dst;//倾斜角度矫正degree CalcDegree(src, dst);rotateImage(src, dst, degree);cout angle: degree endl;imshow(旋转调整后, dst);Mat resulyImage dst(Rect(0, 0, dst.cols, 1000)); //根据先验知识估计好文本的长宽再裁剪下来imshow(裁剪之后, resulyImage);imwrite(recified.jpg, resulyImage);
}int main()
{ImageRecify(test.jpg, FinalImage.jpg);waitKey();return 0;
}
4.检测矩形轮廓 角度 旋转
#include opencv2/imgproc.hpp
#include opencv2/highgui.hpp
#include iostream
using namespace cv;
using namespace std;
#include algorithmbool x_sort(const Point2f m1, const Point2f m2)
{return m1.x m2.x;
}//第一个参数输入图片名称第二个参数输出图片名称
void GetContoursPic(const char* pSrcFileName, const char* pDstFileName)
{Mat srcImg imread(pSrcFileName);imshow(原始图, srcImg);Mat gray, binImg;//灰度化cvtColor(srcImg, gray, COLOR_RGB2GRAY);imshow(灰度图, gray);//二值化threshold(gray, binImg, 150, 200, CV_THRESH_BINARY);imshow(二值化, binImg);vectorPoint contours;vectorvectorPoint f_contours;//注意第5个参数为CV_RETR_EXTERNAL只检索外框 findContours(binImg, f_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //找轮廓int max_area 0;int index;for (int i 0; i f_contours.size(); i){double tmparea fabs(contourArea(f_contours[i]));if (tmparea max_area){index i;max_area tmparea;}}contours f_contours[index];CvBox2D rect minAreaRect(Mat(contours));float angle rect.angle;cout before angle : angle endl;if (angle -45)angle (90 angle);elseangle -angle;cout after angle : angle endl;//新建一个感兴趣的区域图大小跟原图一样大 Mat RoiSrcImg(srcImg.rows, srcImg.cols, CV_8UC3); //注意这里必须选CV_8UC3RoiSrcImg.setTo(0); //颜色都设置为黑色 //imshow(新建的ROI, RoiSrcImg);//对得到的轮廓填充一下 drawContours(binImg, f_contours, 0, Scalar(255), CV_FILLED);//抠图到RoiSrcImgsrcImg.copyTo(RoiSrcImg, gray);//再显示一下看看除了感兴趣的区域其他部分都是黑色的了 namedWindow(RoiSrcImg, 1);imshow(RoiSrcImg, RoiSrcImg);//创建一个旋转后的图像 Mat RatationedImg(RoiSrcImg.rows, RoiSrcImg.cols, CV_8UC1);RatationedImg.setTo(0);//对RoiSrcImg进行旋转 Point2f center rect.center; //中心点 Mat M2 getRotationMatrix2D(center, angle, 1);//计算旋转加缩放的变换矩阵 warpAffine(RoiSrcImg, RatationedImg, M2, RoiSrcImg.size(), 1, 0, Scalar(0));//仿射变换 imshow(旋转之后, RatationedImg);
}void main()
{GetContoursPic(34.png, FinalImage.jpg);waitKey();
}opencv4.x
#include opencv2/imgproc.hpp
#include opencv2/highgui.hpp
#include opencv2/imgproc/types_c.h
#include opencv2/imgproc/imgproc.hpp
#include opencv2/highgui/highgui.hpp
#include iostreamusing namespace cv;
using namespace std;
#include algorithmbool x_sort(const Point2f m1, const Point2f m2)
{return m1.x m2.x;
}//第一个参数输入图片名称第二个参数输出图片名称
void GetContoursPic(const char* pSrcFileName, const char* pDstFileName)
{Mat srcImg imread(pSrcFileName);imshow(原始图, srcImg);Mat gray, binImg;//灰度化cvtColor(srcImg, gray, COLOR_RGB2GRAY);imshow(灰度图, gray);//二值化threshold(gray, binImg, 150, 200, cv::THRESH_BINARY);imshow(二值化, binImg);vectorPoint contours;vectorvectorPoint f_contours;//注意第5个参数为CV_RETR_EXTERNAL只检索外框 findContours(binImg, f_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //找轮廓int max_area 0;int index;for (int i 0; i f_contours.size(); i){double tmparea fabs(contourArea(f_contours[i]));if (tmparea max_area){index i;max_area tmparea;}}contours f_contours[index];RotatedRect rect minAreaRect(Mat(contours));float angle rect.angle;cout before angle : angle endl;if (angle -45)angle (90 angle);elseangle -angle;cout after angle : angle endl;//新建一个感兴趣的区域图大小跟原图一样大 Mat RoiSrcImg(srcImg.rows, srcImg.cols, CV_8UC3); //注意这里必须选CV_8UC3RoiSrcImg.setTo(0); //颜色都设置为黑色 //imshow(新建的ROI, RoiSrcImg);//对得到的轮廓填充一下 drawContours(binImg, f_contours, 0, Scalar(255), cv::FILLED);//抠图到RoiSrcImgsrcImg.copyTo(RoiSrcImg, gray);//再显示一下看看除了感兴趣的区域其他部分都是黑色的了 namedWindow(RoiSrcImg, 1);imshow(RoiSrcImg, RoiSrcImg);//创建一个旋转后的图像 Mat RatationedImg(RoiSrcImg.rows, RoiSrcImg.cols, CV_8UC1);RatationedImg.setTo(0);//对RoiSrcImg进行旋转 Point2f center rect.center; //中心点 Mat M2 getRotationMatrix2D(center, angle, 1);//计算旋转加缩放的变换矩阵 warpAffine(RoiSrcImg, RatationedImg, M2, RoiSrcImg.size(), 1, 0, Scalar(0));//仿射变换 imshow(旋转之后, RatationedImg);imwrite(recified.jpg, RatationedImg);
}int main()
{GetContoursPic(test.jpg, FinalImage.jpg);waitKey();return 0;
}参考
榴莲小怪兽 opencv-图片矫正