基于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;
}