OpenCV
来源:互联网 发布:机器人软件编程 编辑:程序博客网 时间:2024/06/04 20:07
利用OpenCV的功能可以方便快捷的将图片里面的文字纠正过来:
文章是参考国外帖子来写的:http://felix.abecassis.me/2011/09/opencv-detect-skew-angle/
这里有我的一些iOS, Mac代码和测试结果,可以方便的自动旋转文字方向,旋转图片。
图片有一些前提,或者处理缺陷:
1、图片没有外边框干扰
2、倒立或者竖着的图片,纠正后还是倒立,或者竖着的。
比如以下这2个图片,纠正后结果都不理想:
会旋转,但是纠正后会竖立,需要进一步判断。
计算的纠正角度为0,纠正失败。
方法一、利用线条横线计算角度,然后再纠正。
// 参考 Félix Abecassis - OpenCV - Detect skew angle// http://felix.abecassis.me/2011/09/opencv-detect-skew-angle/+ (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("/Users/James/Desktop/skew-lines.bmp", disp_lines); fprintf(stderr, "ImageSkewAngle result: %f\n", angle); return angle;}
方法二、利用文字最小区域获取矩形计算角度,然后再纠正。
// 参考 Félix Abecassis - OpenCV - Bounding Box & Skew Angle// http://felix.abecassis.me/2011/10/opencv-bounding-box-skew-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("/Users/James/Desktop/skew-bin.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("/Users/James/Desktop/skew-erode.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("/Users/James/Desktop/skew-rect.bmp", image); } fprintf(stderr, "ImageSkewAngle result: %f\n", angle); return angle;}+ (double)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 0.0f; } if(image.channels() != 1){ fprintf(stderr, "error: src.channels() != 1\n"); return 0.0f; } //中值滤波器是一种非线性滤波器,常用于消除图像中的椒盐噪声。与低通滤波不同的是,中值滤波有利于保留边缘的尖锐度,但它会洗去均匀介质区域中的纹理。 //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_INV); // 二值化效果好 return [RecognitionManager cvMatImageSkewAngleWithImageBin:image];}
最后是纠正图片的方法:
// 参考 Félix Abecassis - OpenCV - Rotation (Deskewing)// http://felix.abecassis.me/2011/10/opencv-rotation-deskewing/+ (cv::Mat)cvMatImageDeskew:(cv::Mat)src angle:(double)angle;{ cv::Mat img = src.clone(); cv::imwrite("/Users/James/Desktop/deskew-src.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("/Users/James/Desktop/deskew-rotated.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("/Users/James/Desktop/deskew-cropped.bmp", cropped); } return rotated; }
测试代码:
- (void)deskew{ if(1){ cv::Mat gray_image = [RecognitionManager cvMatImageFromCGImageRef_Grayscale:[[imageView image] CGImage_FPLib]]; //double angle = [RecognitionManager cvMatImageSkewAngleWithImageGray:gray_image]; double angle = [RecognitionManager cvMatImageSkewAngleUsingSHT:gray_image]; cv::Mat img_deskew; img_deskew = [RecognitionManager cvMatImageDeskew:gray_image angle:angle]; imageView.image = [NSImage imageWithCGImage_FPLib:[RecognitionManager CGImageRefFromCVMat:img_deskew]]; } }
原图:
方法一、
方法二:
更多测试:
原图:
方法二结果:
结果是误旋转了:-(。
可以看出,方法一、对于边框有干扰,无法正确纠正。
方法二、要比方法一适应性强,但是也有边框干扰,都会有一些误操作。
其实还有一种方法就是利用findContours查找最大边框,然后利用图片裁剪函数纠正。
https://stackoverflow.com/questions/8667818/opencv-c-obj-c-detecting-a-sheet-of-paper-square-detection?noredirect=1&lq=1
阅读全文
0 0
- opencv
- openCV
- openCV
- Opencv
- opencv
- opencv
- opencv
- OpenCV
- OpenCV
- OpenCV
- OpenCV
- opencv
- Opencv。。
- OpenCV
- opencv
- opencv
- opencv
- opencv
- C#知识点整理(1)-委托
- SpringMVC上传文件
- 线程同步基础(二)
- iOS数据存储方法大全
- 【设计】单例模式--C++源代码(VS2015)
- OpenCV
- 各大公司笔试面试经-Java软件工程师
- delphi 基于模型驱动的表单拓展组件的设计与实现。
- BZOJ3750: [POI2015]Pieczęć
- 关于Xcode9拖拽文件无法识别
- Centos7更改默认启动模式
- 我女朋友是个程序员……# 1
- 招了一层楼的程序员,东西却做不好?
- 绝对安全的加密方法……