基于OpenCV(C++)的视觉检测

基于OpenCV(C++)的视觉检测

详细见:基于OpenCV的 桌面手机的尺寸测量_Aquamarine__的博客-CSDN博客

校正见:校正 + 旋转校正 OpenCV (C++)_Aquamarine__的博客-CSDN博客_c++图像旋转校正


#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>//higngui头文件
#include <opencv2/imgcodecs.hpp>//opencv 图像处理头文件
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;

static cv::Point2f midpoint(cv::Point2f& ptA, cv::Point2f& ptB);//求中点 
static float getDistance(Point2f pointA, Point2f pointB);//求距离
static bool ContoursSortFun(vector<cv::Point> contour1, vector<cv::Point> contour2);//按照 x坐标 排序

bool g_bFirst = true;
double g_dPixelsPerMetric;
//const int g_dReferWidth = 19;//一角的是19mm
const int g_dReferWidth = 25;//一元的是25mm


int main()
{
	//载入原图
	Mat img = imread("C:\\Users\\30279\\Desktop\\identify_size\\4.jpg");

	resize(img, img,img.size()/4);  //对图片进行缩放
	//imshow("原图",img);  //显示原图
	Mat img2 = img;
	

	Mat img_new;//定义一个新的图像对象,以便将处理后的图片赋给他
	Mat img_dst;//定义新图像对象,用于输出模糊处理。
	Mat img_gray;//灰度对象
	Mat img_canny;//用于边缘检测的输出

	//获取图像物体的边缘参数Canny检测(勾出轮廓)
	cvtColor(img, img_gray, COLOR_RGB2GRAY);//灰度化
	//imshow("灰度化", img_gray);
	//threshold(img_gray,img_gray,100,255,THRESH_BINARY); //二值化(一角)
	adaptiveThreshold(img_gray, img_gray,255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 11, 5); //二值化(一元)
	//imshow("二值化", img_gray);
	GaussianBlur(img_gray, img_gray, Size(23, 23), 0, 0);//高斯过滤
	//imshow("img_Gauss", img_gray);
	Canny(img_gray, img_canny, 5, 15, 3);//调用Canny检测边缘
	//imshow("Canny", img_canny);

	//膨胀腐蚀,使之边缘连接
	img2 = getStructuringElement(MORPH_RECT, Size(15, 15));//使用该函数进行指定;形状或尺寸的结构元素(内核矩阵)
	dilate(img_canny, img_new, img2);	//对图像进行膨胀处理
	erode(img_new, img_new, getStructuringElement(MORPH_RECT, Size(15,15)));    //图像腐蚀函数
	//imshow("膨胀腐蚀后", img_new);
	
	/************************** 轮廓查找 *************************/
	//初始化结果图
	Mat dst = Mat::zeros(img.rows, img.cols, CV_8UC3);
	//取大于阈值119的那部分
	//img = img > 119;
	//定义轮廓和层次结构
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	//查找轮廓
	findContours(img_new, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE);
	//遍历所有顶层的轮廓,以随机颜色绘制出每个连接组件颜色
	int index = 0;
	for (; index >= 0; index = hierarchy[index][0]) {
		Scalar color = (0,0,255);
		drawContours(img_new, contours, index, color, FILLED, 8, hierarchy);
	}
	findContours(img_new, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_NONE);
	drawContours(img, contours, -1, Scalar(255, 0, 0), 3, 8, hierarchy);
	//显示最后的轮廓图
	//imshow("after", img);

	std::sort(contours.begin(), contours.end(), ContoursSortFun);//按照从左到右 排序
	for (unsigned i = 0; i < contours.size(); i++) {
		if (contourArea(contours[i]) < 100)//面积太小 则忽略
			continue;

		RotatedRect box = minAreaRect(contours[i]);
		Point2f boxPoints[4];
		box.points(boxPoints);

		Point2f pointA = midpoint(boxPoints[0], boxPoints[1]);
		Point2f pointB = midpoint(boxPoints[1], boxPoints[2]);
		Point2f pointC = midpoint(boxPoints[2], boxPoints[3]);
		Point2f pointD = midpoint(boxPoints[3], boxPoints[0]);

		circle(img, pointA, 2, Scalar(0, 0, 255));
		circle(img, pointB, 2, Scalar(0, 0, 255));
		circle(img, pointC, 2, Scalar(0, 0, 255));
		circle(img, pointD, 2, Scalar(0, 0, 255));

		line(img, pointA, pointC, Scalar(255, 0, 0));
		line(img, pointD, pointB, Scalar(255, 0, 0));

		double dWidth = getDistance(pointA, pointC);
		double dHeight = getDistance(pointD, pointB);
		if (g_bFirst) {
			g_dPixelsPerMetric = dWidth / g_dReferWidth; //计算像素与 实际大小的比列
			cout << "pixelPerMetric:" << dWidth << " " << g_dReferWidth << "  " << g_dPixelsPerMetric;
			g_bFirst = false;
		}
		cout << "dWidth" << dWidth << "   " << dHeight << "      " << dWidth / g_dPixelsPerMetric << "    " << dHeight / g_dPixelsPerMetric;
		putText(img, cv::format("(%.0f,%.0f)", dWidth / g_dPixelsPerMetric, dHeight / g_dPixelsPerMetric), boxPoints[2], FONT_HERSHEY_COMPLEX, 0.5, Scalar(0, 0, 255));
		for (int i = 0; i <= 3; i++)
		{
			line(img, boxPoints[i], boxPoints[(i + 1) % 4], Scalar(0, 255, 0));
		}
	}
	cv::namedWindow("效果", WINDOW_AUTOSIZE);
	cv::imshow("效果", img);


	/************************************倾斜校正*********************************/
	//vector<Rect> boundRect(contours.size());
	//vector<RotatedRect> box(contours.size());
	//Point2f rect[4];  //定义数组存放四个顶点
	//for (int i = 0; i < contours.size(); i++) {
	//	box[i] = minAreaRect(Mat(contours[i]));
	//	//boundRect[i] = boundingRect(Mat(contours[i]));  //计算轮廓的最小外接矩形
	//	//if (box[i].size.width < 100 || box[i].size.height < 100)//筛选
	//	//	continue;
	//	画一个矩形
	//	//rectangle(img_new, Point(boundRect[i].x, boundRect[i].y), Point(boundRect[i].x + boundRect[i].width, boundRect[i].y + boundRect[i].height), Scalar(0, 255, 0), 2, 8);
	//	//circle(img_new, Point(box[i].center.x, box[i].center.y), 5, Scalar(0, 255, 0), -1, 8);
	//	//box[i].points(rect);
	//	//for (int j = 0; j < 4; j++) {
	//	//	line(img_new, rect[j], rect[(j + 1) % 4], Scalar(0, 0, 255), 2, 8);
	//	//}
	//	float angle;
	//	angle = box[i].angle;
	//	char width[20], height[20];
	//	//利用仿射变换进行旋转  
	//	if (0 < abs(angle) && abs(angle) <= 45)
	//		angle = angle;//负数,顺时针旋转
	//	else if (45 < abs(angle) && abs(angle) < 90)
	//		angle = 90 - abs(angle);//正数,逆时针旋转
	//	Point2f center = box[i].center;  //定义旋转中心坐标
	//	double angle0 = angle;
	//	double scale = 1;
	//	Mat roateM = getRotationMatrix2D(center, angle0, scale);  //获得旋转矩阵,顺时针为负,逆时针为正
	//	warpAffine(img_new, img_new, roateM, img_new.size()); //仿射变换

	//	imshow("11", img_new);


	//}


	//Point2f srcTri[3];
	//Point2f dstTri[3];
	设置源图像和目标图像上的三组点以计算仿射变换
	//srcTri[0] = Point2f(0, 0);
	//srcTri[1] = Point2f(img_new.cols - 1, 0);
	//srcTri[2] = Point2f(0, img_new.rows - 1);
	//dstTri[0] = Point2f(img_new.cols*0.0, img_new.rows*0.33);
	//dstTri[1] = Point2f(img_new.cols*0.85, img_new.rows*0.25);
	//dstTri[2] = Point2f(img_new.cols*0.15, img_new.rows*0.7);
	 设置目标图像的大小和类型与源图像一致
	//Mat warp_dst = Mat::zeros(img_new.rows, img_new.cols, img_new.type());
	求得仿射变换
	//Mat warp_mat = getAffineTransform(srcTri, dstTri);
	对源图像应用上求得的仿射变换
	//warpAffine(img_new, warp_dst, warp_mat, warp_dst.size());
	 对图像扭曲后再旋转
 //   // 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
	//Point center = Point(warp_dst.cols / 2, warp_dst.rows / 2);
	//double angle = -50.0;
	//double scale = 0.6;
	 通过上面的旋转细节信息求得旋转矩阵
	//Mat rot_mat = getRotationMatrix2D(center, angle, scale);
	 旋转已扭曲图像
	//Mat warp_rotate_dst;
	//warpAffine(warp_dst, warp_rotate_dst, rot_mat, warp_dst.size());
	 显示结果
	//imshow("source_window", img_new);
	//imshow("warp_window", warp_dst);
	//imshow("warp_rotate_window", warp_rotate_dst);

	waitKey(0);
	return 0;
}

Point2f midpoint(Point2f& ptA, Point2f& ptB) {
	return Point2f((ptA.x + ptB.x)*0.5, (ptA.y + ptB.y)*0.5);
}

bool ContoursSortFun(vector<cv::Point> contour1, vector<cv::Point> contour2) {
	return  (contour1[0].x < contour2[0].x); // a.x < b.x;
}

float getDistance(Point2f pointA, Point2f pointB) {
	float distance;
	distance = powf((pointA.x - pointB.x), 2) + powf((pointA.y - pointB.y), 2);
	distance = sqrtf(distance);
	return distance;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值