OpenCV影象角度矯正
阿新 • • 發佈:2018-12-10
影象角度矯正原始碼
/高升教我的一二三事 #include<iostream> #include<string> #include<sstream> #include"dllpic.h" using namespace std; #include "opencv2/opencv.hpp" using namespace cv; int _stdcall Add(int n1, int n2) { // int Add(int n1, int n2) { return (n1 + n2); } int _stdcall Minus(int n1, int n2) { // int Add(int n1, int n2) { return (n1 - n2); } //方法- double cvMatImageSkewAngleUsingSHT(cv::Mat gray) { // Load in grayscale. //cv::Mat src = cv::imread(filename, cv::IMREAD_GRAYSCALE) if (gray.data == NULL) { fprintf(stderr, "error: src.data == NULL\n"); return 0.0f; } if (gray.channels() != 1) { fprintf(stderr, "error: src.channels() != 1\n"); return 0.0f; } cv::bitwise_not(gray, gray); cv::Size size = gray.size(); // 需要的是黑色背景 std::vector<cv::Vec4i> lines; cv::HoughLinesP(gray, lines, 1, CV_PI / 180, 100, size.width / 2.f, 20); cv::Mat disp_lines(size, CV_8UC1, cv::Scalar(0, 0, 0)); double angle = 0.; unsigned nb_lines = lines.size(); for (unsigned i = 0; i < nb_lines; ++i) { cv::line(disp_lines, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(255, 0, 0)); angle += atan2((double)lines[i][3] - lines[i][1], (double)lines[i][2] - lines[i][0]); } angle /= nb_lines; // mean angle, in radians. angle = angle * 180 / CV_PI; cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle1.bmp", disp_lines); fprintf(stderr, "ImageSkewAngle result: %f\n", angle); return angle; } //方法二 double cvMatImageSkewAngleWithImageBin(cv::Mat image_bin) { // 輸入的是黑底白字圖片 cv::Mat image = image_bin.clone(); if (image.data == NULL) { fprintf(stderr, "error: src.data == NULL\n"); return 0.0f; } if (image.channels() != 1) { fprintf(stderr, "error: src.channels() != 1\n"); return 0.0f; } cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle2.bmp", image); // Size(23, 3)); Size(5, 3));,使用Size(3, 3)最好 cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); // 最基本的形態學操作有二:腐蝕與膨脹(Erosion 與 Dilation) cv::erode(image, image, element); cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle3.bmp", image); std::vector<cv::Point> points; cv::Mat_<uchar>::iterator it = image.begin<uchar>(); cv::Mat_<uchar>::iterator end = image.end<uchar>(); for (; it != end; ++it) if (*it) points.push_back(it.pos()); cv::RotatedRect box = cv::minAreaRect(cv::Mat(points)); double angle = box.angle; if (angle < -45.) angle += 90.; if (1) { cv::Point2f vertices[4]; box.points(vertices); for (int i = 0; i < 4; ++i) cv::line(image, vertices[i], vertices[(i + 1) % 4], cv::Scalar(255, 0, 0), 1, CV_AA); cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle4.bmp", image); } fprintf(stderr, "ImageSkewAngle result: %f\n", angle); return angle; } cv::Mat cvMatImageSkewAngleWithImageGray(cv::Mat image_gray) { // 輸入的是灰度圖片 // Load in grayscale. //cv::Mat img = cv::imread(filename, cv::IMREAD_GRAYSCALE); cv::Mat image = image_gray.clone(); if (image.data == NULL) { fprintf(stderr, "error: src.data == NULL\n"); return cv::Mat(); } if (image.channels() != 1) { fprintf(stderr, "error: src.channels() != 1\n"); return cv::Mat(); } //中值濾波器是一種非線性濾波器,常用於消除影象中的椒鹽噪聲。與低通濾波不同的是,中值濾波有利於保留邊緣的尖銳度,但它會洗去均勻介質區域中的紋理。 //cv::medianBlur(img, img, 3); //cv::GaussianBlur(img, img, cv::Size(3, 3), 0); //GaussianBlur(img, img, cvSize(11,11), 0);//change from median blur to gaussian for more accuracy of square detection // Binarize //cv::threshold(img, img, 225, 255, CV_THRESH_BINARY_INV); cv::threshold(image, image, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); // 二值化效果好 return image; } cv::Mat cvMatImageDeskew(cv::Mat src , double angle) { cv::Mat img = src.clone(); cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle6.bmp", img); cv::Mat cropped; cv::Mat rotated; // Load in grayscale. //cv::Mat img = cv::imread(filename, cv::IMREAD_GRAYSCALE); if (img.data == NULL) { fprintf(stderr, "error: src.data == NULL"); return rotated; } if (img.channels() != 1) { fprintf(stderr, "error: src.channels() != 1"); return rotated; } std::vector<cv::Point> points; cv::Mat_<uchar>::iterator it = img.begin<uchar>(); cv::Mat_<uchar>::iterator end = img.end<uchar>(); for (; it != end; ++it) if (*it) points.push_back(it.pos()); cv::RotatedRect box = cv::minAreaRect(cv::Mat(points)); cv::Mat rot_mat = cv::getRotationMatrix2D(box.center, angle, 1); // 旋轉 cv::warpAffine(img, rotated, rot_mat, img.size(), cv::INTER_CUBIC); // 預設是黑色背景 //cv::warpAffine(img, rotated, rot_mat, img.size(), CV_INTER_CUBIC, cv::BORDER_CONSTANT, cvScalarAll(0)); // 黑色背景 //cv::warpAffine(img, rotated, rot_mat, img.size(), cv::INTER_CUBIC, cv::BORDER_CONSTANT, cvScalar(255, 255, 255)); // 白色背景 cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle7.bmp", rotated); if (0) { // 切割 cv::Size box_size = box.size; if (box.angle < -45.) std::swap(box_size.width, box_size.height); cv::getRectSubPix(rotated, box_size, box.center, cropped); cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle8.bmp", cropped); } return rotated; } int main(int argc, const char ** argv) { double angle = 0; string fileStr = "E:/OpenCv/jiaozhengPic/pic/5angle.bmp"; Mat src = imread(fileStr, 0); Mat gray = imread(fileStr, 0); angle = cvMatImageSkewAngleUsingSHT(gray); //方法二 /*bitwise_not(gray, gray); gray = cvMatImageSkewAngleWithImageGray(gray); angle = cvMatImageSkewAngleWithImageBin(gray); */ cvMatImageDeskew(src, angle); return 0; }