F:\学科、技能、编程\【编程-文件\proj\圆弧检测(opencv-qt)
可以自动或者手动测量圆弧液柱的角度:
使用说明 :
找圆心(最小二乘拟合)相关代码
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
bool circleLeastFit(CvSeq* points, double ¢er_x, double ¢er_y, double &radius);//最小二乘法拟合函数
int main()
{
const char* winname ="winname";
//const char* winname1 ="winname1";
//const char* winname2 ="winname2";
//const char* winname3 ="winname3";
char * picname = "P11.jpg";
//加载原图
IplImage * pImage = cvLoadImage(picname);
//分量图像
IplImage *pR = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
IplImage *pG = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
IplImage *pB = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
IplImage *temp = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
IplImage *binary = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1);
//trackbar的变量值 //对应各个通道
int b_low =20;
int b_high = 100;
int g_low = 20;
int g_high = 100;
int r_low = 0;
int r_high = 100;
//轮廓相关
CvMemStorage *storage = cvCreateMemStorage(0);
CvSeq * seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
//窗口
cvNamedWindow(winname);
cvShowImage(winname, pImage); //显示原图
cvNamedWindow("r",2);
cvNamedWindow("g",2);
cvNamedWindow("b",2); //各个通道
cvNamedWindow("binary",2);//二值化图
//在相应的窗口建立滑动条
cvCreateTrackbar( "b1","b", &b_low, 254, NULL); //H通道分量范围0-180
cvSetTrackbarPos("b1","b",0 ); //设置默认位置
cvCreateTrackbar( "b2","b", &b_high, 254, NULL);//H通道分量范围0-180
cvSetTrackbarPos("b2","b",110 );
cvCreateTrackbar( "g1","g", &g_low, 254, NULL);
cvSetTrackbarPos("g1","g",0 );
cvCreateTrackbar( "g2","g", &g_high, 254, NULL);
cvSetTrackbarPos("g2","g",158 );
cvCreateTrackbar( "r1","r", &r_low, 254, NULL);
cvSetTrackbarPos("r1","r",68 );
cvCreateTrackbar( "r2","r", &r_high, 254, NULL);
cvSetTrackbarPos("r2","r",137);
while(1)
{
//各个通道分离
cvSplit(pImage,pB,pG,pR,NULL);
//阈值化
cvThreshold(pB, temp,b_low , 255, CV_THRESH_BINARY);
cvThreshold(pB, pB,b_high , 255, CV_THRESH_BINARY_INV);
cvAnd(temp,pB,pB,NULL);//与操作,合成一张图
cvThreshold(pG, temp,g_low , 255, CV_THRESH_BINARY);
cvThreshold(pG, pG,g_high , 255, CV_THRESH_BINARY_INV);
cvAnd(temp,pG,pG,NULL);//与操作,合成一张图
cvThreshold(pR, temp,r_low , 255, CV_THRESH_BINARY);
cvThreshold(pR, pR,r_high , 255, CV_THRESH_BINARY_INV);
cvAnd(temp,pR,pR,NULL);//与操作,合成一张图
//显示各个通道的图像
cvShowImage("b",pB);
cvShowImage("g",pG);
cvShowImage("r",pR);
//合成到一张图里
cvAnd(pB, pG, binary, NULL);
cvAnd(pR, binary, binary, NULL);
//膨胀腐蚀操作去除黑点
//cvDilate(binary,binary);
//cvErode(binary,binary);
//显示合成的二值化图
cvShowImage("binary",binary);
//cvSaveImage("erzhitu.jpg",binary);
// 处理轮廓
int cnt = cvFindContours(binary,storage,&seq,sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);//返回轮廓的数目
CvSeq* _contour =seq;
cout<<"number of contours "<<cnt<<endl;
////////////////////_
//找到长度最大轮廓;
double maxarea=0;
int ind_max = -1;
int m=0;
for( ; seq != 0; seq = seq->h_next )
{
m++;
double tmparea = abs(cvArcLength(seq,CV_WHOLE_SEQ,-1));
//double contArea = fabs(cvContourArea(pcontour,CV_WHOLE_SEQ));
if(tmparea > maxarea)
{
maxarea = tmparea;
ind_max=m;
}
// cout<<"seqfor: "<<seq->total<<endl;
}
m=0;
seq = _contour;
for( ; seq != 0; seq = seq->h_next )
{
m++;
if(m == ind_max)
{
break;
}
}
CvSeq* cur_cont = seq;
cout<<"seq: "<<seq->total<<endl;
cout<<"cur_cont: "<<cur_cont->total<<endl;
//for (int i=0;i<cur_cont->total;++i)
//{
// CvPoint* p = CV_GET_SEQ_ELEM(CvPoint,cur_cont,i);//输出轮廓上点的坐标
// printf("(%d,%d)\n",p->x,p->y);
//}
//cvWaitKey(0);
//建立彩色输出图像
IplImage *pOutlineImage = cvCreateImage(cvGetSize(pImage), IPL_DEPTH_8U, 3);
cvCopy(pImage,pOutlineImage);
//int nLevels = 5;
//获取最大轮廓的凸包点集
CvSeq* hull=NULL;
hull = cvConvexHull2(cur_cont,0,CV_CLOCKWISE,0);
cout<<"hull total points number:"<<hull->total<<endl;
CvPoint pt0 = **(CvPoint**)cvGetSeqElem(hull,hull->total - 1);
for(int i = 0;i<hull->total;++i){
CvPoint pt1 = **(CvPoint**)cvGetSeqElem(hull,i);
cvLine(pOutlineImage,pt0,pt1,CV_RGB(0,0,255));
pt0 = pt1;
}
//最小二乘法拟合圆
double center_x=0;
double center_y=0;
double radius=0;
cout<<"nihe :"<<circleLeastFit(hull, center_x, center_y, radius);
cout<<"canshu: "<<center_x<<endl<<center_y<<endl<<radius<<endl;
//绘制圆
cvCircle(pOutlineImage,Point2f(center_x,center_y),radius,CV_RGB(0,100,100));
//////////////////////////////////////////////////////////////////////////
//绘制轮廓
//cvDrawContours(pOutlineImage, cur_cont, CV_RGB(255,0,0), CV_RGB(0,255,0),0);
//cvDrawContours(dst,contour,CV_RGB(255,0,0),CV_RGB(0,255,0),0);
cvShowImage(winname, pOutlineImage); //显示原图jiangshang luokuo
if (cvWaitKey(1000) == 27)
{
cvSaveImage("tutu.jpg",pOutlineImage);
break;
}
cvClearMemStorage( storage ); //清除轮廓所占用的内存
cvReleaseImage(&pOutlineImage);//清除彩色输出图像
}
cvDestroyAllWindows();
cvReleaseImage(&pImage);
cvReleaseImage(&pR);
cvReleaseImage(&pG);
cvReleaseImage(&pB);
cvReleaseImage(&temp);
cvReleaseImage(&binary);
return 0;
}
//最小二乘法拟合,输出圆心的xy坐标值和半径大小;
bool circleLeastFit(CvSeq* points, double ¢er_x, double ¢er_y, double &radius)
{
center_x = 0.0f;
center_y = 0.0f;
radius = 0.0f;
if (points->total < 3)
{
return false;
}
double sum_x = 0.0f, sum_y = 0.0f;
double sum_x2 = 0.0f, sum_y2 = 0.0f;
double sum_x3 = 0.0f, sum_y3 = 0.0f;
double sum_xy = 0.0f, sum_x1y2 = 0.0f, sum_x2y1 = 0.0f;
int N = points->total ;
for (int i = 0; i < N; i++)
{
CvPoint pt1 = **(CvPoint**)cvGetSeqElem(points,i);
double x =pt1.x;
double y = pt1.y ;
double x2 = x * x;
double y2 = y * y;
sum_x += x;
sum_y += y;
sum_x2 += x2;
sum_y2 += y2;
sum_x3 += x2 * x;
sum_y3 += y2 * y;
sum_xy += x * y;
sum_x1y2 += x * y2;
sum_x2y1 += x2 * y;
}
double C, D, E, G, H;
double a, b, c;
C = N * sum_x2 - sum_x * sum_x;
D = N * sum_xy - sum_x * sum_y;
E = N * sum_x3 + N * sum_x1y2 - (sum_x2 + sum_y2) * sum_x;
G = N * sum_y2 - sum_y * sum_y;
H = N * sum_x2y1 + N * sum_y3 - (sum_x2 + sum_y2) * sum_y;
a = (H * D - E * G) / (C * G - D * D);
b = (H * C - E * D) / (D * D - G * C);
c = -(a * sum_x + b * sum_y + sum_x2 + sum_y2) / N;
center_x = a / (-2);
center_y = b / (-2);
radius = sqrt(a * a + b * b - 4 * c) / 2;
return true;
}
标定相关代码
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;
#define MAX_GRAY_VALUE 255
#define MIN_GRAY_VALUE 0
using namespace cv;
using namespace std;
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
bool check_line_state=false;
IplImage* workImg;
IplImage* imgshow;
CvRect ROI_rect;
IplImage* src=0;
void on_mouse( int event, int x, int y, int flags, void* ustc)
{
CvFont font;
cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA);
if( event == CV_EVENT_LBUTTONDOWN )
{
CvPoint pt = cvPoint(x,y);
char temp[16];
sprintf(temp,"(%d,%d)",pt.x,pt.y);
cout<<"("<<pt.x<<","<<pt.y<<")"<<endl;
x1=pt.x;
y1=pt.y;
cvPutText(src,temp, pt, &font, cvScalar(255, 255, 255, 0));
cvCircle( src, pt, 2,cvScalar(255,0,0,0) ,CV_FILLED, CV_AA, 0 );
cvShowImage( "src", src );
}
}
int main()
{
//获取端点的坐标
src=cvLoadImage("dst7.png",1);
cvNamedWindow("src",1);
cvSetMouseCallback( "src", on_mouse, 0 );
cvShowImage("src",src);
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&src);
return 0;
}
/*
//寻找圆心坐标
int main(int args,char** argv)
{ static double radius;
static int i;
Mat srcImage = imread("dst7.png");
if (!srcImage.data)
return -1;
imshow("srcImage", srcImage);
Mat srcGray;
cvtColor(srcImage, srcGray, COLOR_BGR2GRAY);
//高斯平滑滤波
GaussianBlur(srcGray, srcGray, Size(9, 9), 2,2);
static vector<Vec3f> circles;
//Hough圆检测
HoughCircles(srcGray, circles, CV_HOUGH_GRADIENT,1,srcGray.rows/8,200,16,0,0);
//将得到的结果绘图
for (size_t i = 0; i < circles.size(); i++)
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
cout<<center<<endl;
radius = cvRound(circles[i][2]);
cout<<radius<<endl;
//检测圆中心
circle(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0);
//检测圆轮廓
circle(srcImage, center, radius, Scalar(120, 120, 120), 3, 8, 0);
}
imshow("HoughResult", srcImage);
imwrite("HoughResult.jpg",srcImage);
IplImage* image=cvLoadImage("dst5.png");
int p=0;
int q=0;
for (int k=0;k<=360;k++)
{
double m = 3.1415926535*2*k/360;
CvScalar s;
s=cvGet2D(image,cvRound(circles[i][0])+radius*cos(m),cvRound(circles[i][1])+radius*sin(m));
if(s.val[0]!=255)
{
p++;
q++;
}
else
q++;
cout<<m<<p<<q<<endl;
}
waitKey(0);
return 0;
}
//二值化部分
//otsu函数计算最佳阈值
int otsu(Mat dst){
int i, j;
int tmp;
double u0, u1, w0, w1, u, uk;
double cov;
double maxcov = 0.0;
int maxthread = 0;
int hst[MAX_GRAY_VALUE] = { 0 };
double pro_hst[MAX_GRAY_VALUE] = { 0.0 };
int height = dst.cols;
int width = dst.rows;
//统计每个灰度的数量
for (i = 0; i<width; i++){
for (j = 0; j<height; j++){
tmp = dst.at<uchar>(i, j);
hst[tmp]++;
}
}
//计算每个灰度级占图像中的概率
for (i = MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++)
pro_hst[i] = (double)hst[i] / (double)(width*height);
//计算全局平均灰度值
u = 0.0;
for (i = MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++)
u += i*pro_hst[i];
//统计前景和背景的平均灰度值,并计算类间方差
for (i = MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++){
w0 = 0.0; w1 = 0.0; u0 = 0.0; u1 = 0.0; uk = 0.0;
for (j = MIN_GRAY_VALUE; j < i; j++){
uk += j*pro_hst[j];
w0 += pro_hst[j];//前景占图像画幅比例
}
u0 = uk / w0;//前景平均灰度
w1 = 1 - w0;//背景占图像画幅比例
u1 = (u - uk) / (1 - w0);//背景平均灰度
//计算类间方差
cov = w0*w1*(u1 - u0)*(u1 - u0);
if (cov > maxcov)
{
maxcov = cov;
maxthread = i;
}
}
cout << maxthread << endl;
return maxthread;
}
int main(){
int width, height;
int i, j;
Mat obj = imread("22.jpg");
Mat dst1;
cvtColor(obj, dst1, CV_RGB2GRAY);//灰度化
height = dst1.cols;//计算图像高度
width = dst1.rows;//计算图像宽度
int thd = otsu(dst1);
imshow("原图", dst1);
for (i = 0; i < width; i++)
for (j = 0; j< height; j++)
if (dst1.at<uchar>(i, j) > thd)
dst1.at<uchar>(i, j) = MAX_GRAY_VALUE-1;
else
dst1.at<uchar>(i, j) = MIN_GRAY_VALUE;
imwrite("dst1.png",dst1);
imshow("二值化", dst1);
//膨胀(闭运算消除内部米粒)
Mat dst2=imread("dst1.png");
Mat dst3;
Mat element = getStructuringElement(MORPH_RECT,Size(3,3));
//imshow("闭运算消除内部空隙 原图", dst2);
dilate( dst2,dst3,element); //膨胀
imshow("闭运算消除内部空隙 效果图", dst3);
imwrite("dst3.png",dst3);
//腐蚀(开运算去除毛刺)
Mat dst4=imread("dst3.png");
Mat dst5;
//imshow("开运算去除毛刺 原图",dst4);
erode(dst4,dst5,element);
imshow("开运算去除毛刺 效果图",dst5);
imwrite("dst5.png",dst5);
//边缘检测
Mat dst6=imread("dst5.png");
Mat dst7;
//imshow("边缘检测 原图",dst6);
Canny(dst6,dst7,150.100,3);
imshow("边缘检测 效果图",dst7);
imwrite("dst7.png",dst7);
waitKey(0);
return 0;
}
int main()
{
cv::Mat image, Extractcorner;
cv::vector<cv::Point2f> corners; //用来储存所有角点坐标
cv::Size board_size = cv::Size(7, 7); //标定板每行,每列角点数
image = cv::imread("2.jpg");
Extractcorner = image.clone();
cv::Mat imageGray;
cv::cvtColor(image, imageGray, CV_RGB2GRAY);
bool patternfound = cv::findChessboardCorners(image, board_size, corners, cv::CALIB_CB_FAST_CHECK + cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE);
if (!patternfound)
{
std::cout << "can not find chessboard corners!" << std::endl;
exit(1);
}
else
{
//亚像素精确化
cv::cornerSubPix(imageGray, corners, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
}
//角点检测图像显示
for (int i = 0; i < corners.size(); i++)
{
cv::circle(Extractcorner, corners[i], 5, cv::Scalar(255, 0, 255), 2);
}
cv::imshow("Extractcorner", Extractcorner);
cv::imwrite("Extractcorner.jpg", Extractcorner);
//输出角点坐标
cout<<corners<<endl;
//参考图像
cv::Mat image2, Extractcorner2;
cv::vector<cv::Point2f> corners2; //用来储存所有角点坐标
cv::Size board_size2 = cv::Size(7, 7); //标定板每行,每列角点数
image2 = cv::imread("1.jpg");
Extractcorner2 = image2.clone();
cv::Mat imageGray2;
cv::cvtColor(image2, imageGray2, CV_RGB2GRAY);
bool patternfound2 = cv::findChessboardCorners(image2, board_size, corners2, cv::CALIB_CB_FAST_CHECK + cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE);
if (!patternfound2)
{
std::cout << "can not find chessboard corners!" << std::endl;
exit(1);
}
else
{
//亚像素精确化
cv::cornerSubPix(imageGray2, corners2, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
}
//角点检测图像显示
for (int i = 0; i < corners2.size(); i++)
{
cv::circle(Extractcorner2, corners2[i], 5, cv::Scalar(255, 0, 255), 2);
}
cv::imshow("Extractcorner2", Extractcorner2);
cv::imwrite("Extractcorner2.jpg", Extractcorner2);
//输出角点坐标
cout<<corners2<<endl;
//仿射变换1
Mat src = imread("2.jpg");
Mat dst_warp;
Point2f srcPoints[3];//原图中的三点
Point2f dstPoints[3];//目标图中的三点
//三个点对的值
srcPoints[0] = Point2f(142.52786,115.98566);
srcPoints[1] = Point2f(110.28358,409.29211);
srcPoints[2] = Point2f(438.46851,126.58415);
dstPoints[0] = Point2f(44.506947, 46.233685);
dstPoints[1] = Point2f(44.496399, 325.76706);
dstPoints[2] = Point2f(314.50659, 46.230354);
Mat M1 = getAffineTransform(srcPoints,dstPoints);//由三个点对计算变换矩阵
warpAffine(src,dst_warp,M1,src.size());//仿射变换
imshow("src",src);
imshow("dst_warp",dst_warp);
imwrite("dst_warp.jpg",dst_warp);
//一次变换后图像
cv::Mat image3, Extractcorner3;
cv::vector<cv::Point2f> corners3; //用来储存所有角点坐标
cv::Size board_size3 = cv::Size(7, 7); //标定板每行,每列角点数
image3 = cv::imread("dst_warp.jpg");
Extractcorner3 = image3.clone();
cv::Mat imageGray3;
cv::cvtColor(image3, imageGray3, CV_RGB2GRAY);
bool patternfound3 = cv::findChessboardCorners(image3, board_size, corners3, cv::CALIB_CB_FAST_CHECK + cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE);
if (!patternfound3)
{
std::cout << "can not find chessboard corners!" << std::endl;
exit(1);
}
else
{
//亚像素精确化
cv::cornerSubPix(imageGray3, corners3, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
}
//角点检测图像显示
for (int i = 0; i < corners3.size(); i++)
{
cv::circle(Extractcorner3, corners3[i], 5, cv::Scalar(255, 0, 255), 2);
}
cv::imshow("Extractcorner3", Extractcorner3);
cv::imwrite("Extractcorner3.jpg", Extractcorner3);
//输出角点坐标
cout<<corners3<<endl;
ofstream outfile;
outfile.open("date.txt");
outfile<<corners<<endl<<endl<<endl<<corners2<<corners3<<endl;
outfile.close();
//仿射变换2
Mat src2 = imread("dst_warp.jpg");
Mat dst_warp2;
Point2f src2Points[3];//原图中的三点
Point2f dst2Points[3];//目标图中的三点
//三个点对的值
src2Points[0] = Point2f(395.12207, 306.01523);
src2Points[1] = Point2f(44.515686, 325.73227);
src2Points[2] = Point2f(314.53482, 46.279831);
dst2Points[0] = Point2f(314.49469, 325.76535);
dst2Points[1] = Point2f(44.496399, 325.76706);
dst2Points[2] = Point2f(314.50659, 46.230354);
Mat M2 = getAffineTransform(src2Points,dst2Points);//由三个点对计算变换矩阵
warpAffine(src2,dst_warp2,M2,src2.size());//仿射变换
imshow("src2",src);
imshow("dst_warp2",dst_warp2);
imwrite("dst_warp2.jpg",dst_warp2);
cv::waitKey(0);
return 0;
}
*/