opencv知道四个顶点的座标,截取ROI(C++/opencv3.1)(和C#OpencvSharp版本)

思路:

1.找到最小外接矩形

2.根据面积筛选外接矩形

3.找到自己想要的合适的外接矩形,进行倾斜校正(外接矩形有中心点,偏转角--旋转时中心点座标不变)

4.根据中心点座标,用ROI的Rect方法获取旋转后的ROI

C++代码:

#include "stdio.h"
#include "opencv2/highgui/highgui_c.h"
#include <opencv2/opencv.hpp>
#include <tchar.h>
#include <fstream>
#include <string>
#include <iostream>
#include <math.h>
#include <String>

using namespace std;
using namespace cv;

bool CutPic(string path)
{
	bool status = false;
	string pattern_bmp;
	//vector<String>image_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<vector<Point>> contours;
	vector<Vec4i> 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

C#代码: 

using System;
using System.IO;
using OpenCvSharp;

namespace MultiCamControl
{
	/// <summary>
	/// 剪切图片
	/// </summary>
	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);
		}

	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章