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);
		}

	}
}

 

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