思路:
1.找到最小外接矩形
2.根据面积筛选外接矩形
3.找到自己想要的合适的外接矩形,进行倾斜校正(外接矩形有中心点,偏转角--旋转时中心点坐标不变)
4.根据中心点坐标,用ROI的Rect方法获取旋转后的ROI
#include "stdio.h"
#include "opencv2/highgui/highgui_c.h"
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
bool CutPic(string path)
{
bool status = false;
string pattern_bmp;
//vectorimage_files;
//批量处理时用
//pattern_bmp = "D:\\Project\\num_pic\\*.bmp";
//处理单张绝对路径
//pattern_bmp = "D:\\Project\\mm.bmp";
//传递路径参数时用
//pattern_bmp = path;
//相对路径
pattern_bmp = "./GxSingleCamImages" + string(path) + "/0.bmp";
//绝对路径
//pattern_bmp = "D:\\Project\\Balise\\GxSing\\0.bmp";
//批量获取文件夹中的图片
//glob(pattern_bmp, image_files);
//for (int file_num = 0; file_num< image_files.size(); file_num++)
//{
//Mat img = imread(image_files[file_num]);
//Mat src = imread(image_files[file_num]);
Mat img = imread(pattern_bmp);
Mat src = img.clone();
//namedWindow("原图", 0);
//resizeWindow("原图", 720, 540);
//imshow("原图", src);
//waitKey();
Mat mask = Mat::zeros(src.size(), CV_8UC1);
//Mat dstImg;
Point2f a(0.f, 0.f);
Point2f b(0.f, 0.f);
int index_0 = 0, index_1 = 0;
Mat grayscale, binary;
cvtColor(src, binary, CV_BGR2GRAY);
//blur(灰度图, 二值图, Size(5, 5));//模糊一下,可以不要
threshold(binary, binary, 0, 255, CV_THRESH_OTSU);//自适应二值化
binary = 255 - binary;//颜色反转
namedWindow("二值图", 0);
resizeWindow("二值图", 720, 540);
imshow("二值图", binary);
waitKey();
bool flag = true;
//寻找最外层轮廓
vector> contours;
vector hierarchy;
findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
Mat canvas = Mat::zeros(binary.size(), CV_8UC1); //最小外接矩形画布
for (int i = 0; i < contours.size(); i++)
{
//绘制轮廓
drawContours(canvas, contours, i, Scalar(255), 1, 8, hierarchy);
//绘制轮廓的最小外结矩形
RotatedRect rect = minAreaRect(contours[i]);
//rectangle(画布,rect.boundingRect(),Scalar(55));
//调正矩形框选定的面积
if (rect.size.area() < 160000)
continue;
if (rect.size.area() > 300000)
continue;
//画出矩形框的外线
Point2f P[4];
rect.points(P);
for (int j = 0; j <= 3; j++)
{
line(src, P[j], P[(j + 1) % 4], Scalar(0, 0, 255), 3);
line(canvas, P[j], P[(j + 1) % 4], Scalar(111), 3);
}
cout << rect.size.area() << endl;
//寻找想要的矩形
if (flag)
{
a.y = rect.center.y;
flag = false;
index_0 = i;
}
else
{
b.y = rect.center.y;
index_1 = i;
if (b.y > a.y)
//b = rect.center;
rect = minAreaRect(contours[index_1]);
else
rect = minAreaRect(contours[index_0]);
rect.points(P);
///倾斜校正
Point2f center = rect.center;
Mat rot_mat = getRotationMatrix2D(center, rect.angle, 1.0);//求旋转矩阵
Mat rot_image;
Size dst_sz(img.size());
warpAffine(img, rot_image, rot_mat, dst_sz);//原图像旋转
Mat result1 = rot_image(Rect(center.x - (rect.size.width / 2), center.y - (rect.size.height / 2), rect.size.width, rect.size.height));//提取ROI
//////////找到min_x,min_y,max_x,max_y,再用ROI//////////
//int min_x = P[0].x;
//int min_y = P[0].y;
//int max_x = P[0].x;
//int max_y = P[0].y;
//for (int i = 0; i <= 3; i++)
//{
/*if (min_x > P[i].x)
min_x = P[i].x;*/
/*if (min_y > P[i].y)
min_y = P[i].y;*/
/*if (max_x < P[i].x)
max_x = P[i].x;*/
/*if (max_y < P[i].y)
max_y = P[i].y;*/
//}
//int width = max_x - min_x;
//int height = max_y - min_y;
//Mat roiImg = img(Rect(min_x, min_y, width, height));//提取的关键就是Rect(minX, minY, width, height)
namedWindow("roi", 0);
resizeWindow("roi", 720, 540);
imshow("roi", result1);
waitKey();
//当批保存时用
//imwrite("D:\\Project\\test\\" + to_string(file_num) + ".jpg", roiImg);
//当使用绝对路径保存时用
//imwrite("D:\\Project\\num_pic_pretreat_test\\bb.jpg", roiImg);
imwrite("./GxSingleCamImages" + string(path) + "/1.jpg", result1);
break;
}
}
namedWindow("标注出矩形", 0);
resizeWindow("标注出矩形", 720, 540);
imshow("标注出矩形", canvas);
namedWindow("原图", 0);
resizeWindow("原图", 720, 540);
imshow("原图", src);
waitKey(0);
//}
fstream file;
file.open("./GxSingleCamImages" + string(path) + "/1.jpg", ios::in);
//file.open("D:\\Project\\Balise\\bin\\GxSingle1\\1.jpg", ios::in);
if (file)
status = true;
return status;
}
参考链接:https://blog.csdn.net/flyyufenfei/article/details/79781194
using System;
using System.IO;
using OpenCvSharp;
namespace MultiCamControl
{
///
/// 剪切图片
///
public class Opencv
{
public static void CutPic(string path)
{
//bool status = false;
int[] index = new int[3] { -1, -1, -1 };
RotatedRect rect_0, rect_1, rect_2;
int count = 0;
string pattern_bmp = Directory.GetCurrentDirectory().ToString() + "\\GxSingleCamImages" + path + "\\0.bmp";
string pattern_jpg = Directory.GetCurrentDirectory().ToString() + "\\GxSingleCamImages" + path + "\\1.jpg";
Mat img = Cv2.ImRead(pattern_bmp);
Size size = new Size(1000, 700);
Cv2.Resize(img, img, size);
Mat binary = new Mat();
Cv2.CvtColor(img, binary, ColorConversionCodes.BGR2GRAY); ;
Cv2.Threshold(binary, binary, 0, 255, ThresholdTypes.Otsu);//自适应二值化
binary = 255 - binary;//颜色反转
// Cv2.Canny(binary, binary, 0, 255);
Point[][] contours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(binary, out contours, out hierarchy, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple, null);
Mat canvas = binary;
for (int i = 0; i < hierarchy.Length; i++)
{
Cv2.DrawContours(canvas, contours, i, Scalar.Red, 1, LineTypes.Link8, hierarchy, 4, new Point(10, 10));
RotatedRect rect = Cv2.MinAreaRect(contours[i]);
if (rect.Size.Height * rect.Size.Height < 170000)
continue;
if (rect.Size.Height * rect.Size.Height > 300000)
continue;
//Point[] P = new Point[4];
//int m = 0;
//foreach (Point item in rect.Points())
//{
// P[m] = item;
// m += 1;
//}
//for (int j = 0; j <= 3; j++)
//{
// Cv2.Line(img, P[j], P[(j + 1) % 4], Scalar.Red, 3);
// Cv2.Line(canvas, P[j], P[(j + 1) % 4], Scalar.Black, 3);
//}
index[count] = i;
count++;
if (count == 3)
break;
}
RotatedRect rect_m;
if (count == 2)
{
rect_0 = Cv2.MinAreaRect(contours[index[0]]);
rect_1 = Cv2.MinAreaRect(contours[index[1]]);
Point2f[] P = new Point2f[2];
P[0] = rect_0.Center;
P[1] = rect_1.Center;
int tmp = 0;
if (P[0].Y > P[1].Y)
tmp = 0;
else
tmp = 1;
rect_m = Cv2.MinAreaRect(contours[index[tmp]]);
}
else
{
rect_0 = Cv2.MinAreaRect(contours[index[0]]);
rect_1 = Cv2.MinAreaRect(contours[index[1]]);
rect_2 = Cv2.MinAreaRect(contours[index[2]]);
Point2f[] P = new Point2f[3];
P[0] = rect_0.Center;
P[1] = rect_1.Center;
P[2] = rect_2.Center;
int result = 0;
if (P[0].Y < P[1].Y && P[0].Y < P[2].Y)
result = 0;
else if (P[1].Y < P[0].Y && P[1].Y < P[2].Y)
result = 1;
else
result = 2;
P[result].X = 20000000000000;
if (P[0].X < P[1].X && P[0].X < P[2].X)
result = 0;
else if (P[1].X < P[0].X && P[1].X < P[2].X)
result = 1;
else
result = 2;
rect_m = Cv2.MinAreaRect(contours[index[result]]);
}
double angle = rect_m.Angle;
Size2f si = new Size2f();
if (rect_m.Size.Height > rect_m.Size.Width)
{
angle = angle + 90;
si.Height = rect_m.Size.Width;
si.Width = rect_m.Size.Height;
}
else
{
si.Height = rect_m.Size.Height;
si.Width = rect_m.Size.Width;
}
Mat rot_mat = Cv2.GetRotationMatrix2D(rect_m.Center, angle, 1.0);
Mat rot_image = new Mat();
Cv2.WarpAffine(img, rot_image, rot_mat, img.Size());
Rect roi = new Rect(Convert.ToInt32(rect_m.Center.X - (si.Width / 2)), Convert.ToInt32(rect_m.Center.Y - (si.Height / 2)), Convert.ToInt32(si.Width), Convert.ToInt32(si.Height));
Mat result1 = new Mat(rot_image, roi);
//Cv2.ImShow("兴趣区域", result1);
//Cv2.ResizeWindow("兴趣区域", 600, 400);
//Cv2.WaitKeyEx();
Cv2.ImWrite(pattern_jpg, result1);
}
}
}