OpenCV轮廓检测,计算物体旋转角度
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#define PI 3.1415926
using namespace std;
using namespace cv;
int hough_line(Mat src)
{
//【1】载入原始图和Mat变量定义
Mat srcImage = src;//imread("1.jpg"); //工程目录下应该有一张名为1.jpg的素材图
Mat midImage,dstImage;//临时变量和目标图的定义
//【2】进行边缘检测和转化为灰度图
Canny(srcImage, midImage, 50, 200, 3);//进行一此canny边缘检测
cvtColor(midImage,dstImage, CV_GRAY2BGR);//转化边缘检测后的图为灰度图
//【3】进行霍夫线变换
vector<Vec4i> lines;//定义一个矢量结构lines用于存放得到的线段矢量集合
HoughLinesP(midImage, lines, 1, CV_PI/180, 80, 50, 10 );
//【4】依次在图中绘制出每条线段
for( size_t i = 0; i < lines.size(); i++ )
{
Vec4i l = lines[i];
line( dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186,88,255), 1, CV_AA);
}
//【5】显示原始图
imshow("【原始图】", srcImage);
//【6】边缘检测后的图
imshow("【边缘检测后的图】", midImage);
//【7】显示效果图
imshow("【效果图】", dstImage);
//waitKey(0);
return 0;
}
int main()
{
// Read input binary image
char *image_name = "c:\\img\\1.bmp";
cv::Mat image = cv::imread(image_name,0);
if (!image.data)
return 0;
cv::namedWindow("Binary Image");
cv::imshow("Binary Image",image);
// 从文件中加载原图
IplImage *pSrcImage = cvLoadImage(image_name, CV_LOAD_IMAGE_UNCHANGED);
// 转为2值图
cvThreshold(pSrcImage,pSrcImage,200,255,cv::THRESH_BINARY_INV);
image = cv::Mat(pSrcImage,true);
cv::imwrite("binary.jpg",image);
// Get the contours of the connected components
std::vector<std::vector<cv::Point>> contours;
cv::findContours(image,
contours, // a vector of contours
CV_RETR_EXTERNAL, // retrieve the external contours
CV_CHAIN_APPROX_NONE); // retrieve all pixels of each contours
// Print contours' length
std::cout << "Contours: " << contours.size() << std::endl;
std::vector<std::vector<cv::Point>>::const_iterator itContours= contours.begin();
for ( ; itContours!=contours.end(); ++itContours)
{
std::cout << "Size: " << itContours->size() << std::endl;
}
// draw black contours on white image
cv::Mat result(image.size(),CV_8U,cv::Scalar(255));
cv::drawContours(result,contours,
-1, // draw all contours
cv::Scalar(0), // in black
2); // with a thickness of 2
cv::namedWindow("Contours");
cv::imshow("Contours",result);
// Eliminate too short or too long contours
int cmin= 100; // minimum contour length
int cmax= 1000; // maximum contour length
std::vector<std::vector<cv::Point>>::const_iterator itc= contours.begin();
while (itc!=contours.end()) {
if (itc->size() < cmin || itc->size() > cmax)
itc= contours.erase(itc);
else
++itc;
}
// draw contours on the original image
cv::Mat original= cv::imread(image_name);
cv::drawContours(original,contours,
-1, // draw all contours
cv::Scalar(255,255,0), // in white
2); // with a thickness of 2
cv::namedWindow("Contours on original");
cv::imshow("Contours on original",original);
// Let's now draw black contours on white image
result.setTo(cv::Scalar(255));
cv::drawContours(result,contours,
-1, // draw all contours
cv::Scalar(0), // in black
1); // with a thickness of 1
image= cv::imread("binary.jpg",0);
//imshow("lll",result);
//waitKey(0);
// testing the bounding box
//////////////////////////////////////////////////////////////////////////////
//霍夫变换进行直线检测,此处使用的是probabilistic Hough transform(cv::HoughLinesP)而不是standard Hough transform(cv::HoughLines)
cv::Mat result_line(image.size(),CV_8U,cv::Scalar(255));
result_line = result.clone();
hough_line(result_line);
//Mat tempimage;
//【2】进行边缘检测和转化为灰度图
//Canny(result_line, tempimage, 50, 200, 3);//进行一此canny边缘检测
//imshow("canny",tempimage);
//waitKey(0);
//cvtColor(tempimage,result_line, CV_GRAY2BGR);//转化边缘检测后的图为灰度图
vector<Vec4i> lines;
cv::HoughLinesP(result_line,lines,1,CV_PI/180,80,50,10);
for(int i = 0; i < lines.size(); i++)
{
line(result_line,cv::Point(lines[i][0],lines[i][1]),cv::Point(lines[i][2],lines[i][3]),Scalar(0,0,0),2,8,0);
}
cv::namedWindow("line");
cv::imshow("line",result_line);
//waitKey(0);
/////////////////////////////////////////////////////////////////////////////////////////////
//
//std::vector<std::vector<cv::Point>>::const_iterator itc_rec= contours.begin();
//while (itc_rec!=contours.end())
//{
// cv::Rect r0= cv::boundingRect(cv::Mat(*(itc_rec)));
// cv::rectangle(result,r0,cv::Scalar(0),2);
// ++itc_rec;
//}
//cv::namedWindow("Some Shape descriptors");
//cv::imshow("Some Shape descriptors",result);
CvBox2D End_Rage2D;
CvPoint2D32f rectpoint[4];
CvMemStorage *storage = cvCreateMemStorage(0); //开辟内存空间
CvSeq* contour = NULL; //CvSeq类型 存放检测到的图像轮廓边缘所有的像素值,坐标值特征的结构体以链表形式
cvFindContours( pSrcImage, storage, &contour, sizeof(CvContour),CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);//这函数可选参数还有不少
for(; contour; contour = contour->h_next) //如果contour不为空,表示找到一个以上轮廓,这样写法只显示一个轮廓
//如改为for(; contour; contour = contour->h_next) 就可以同时显示多个轮廓
{
End_Rage2D = cvMinAreaRect2(contour);
//代入cvMinAreaRect2这个函数得到最小包围矩形 这里已得出被测物体的角度,宽度,高度,和中点坐标点存放在CvBox2D类型的结构体中,
//主要工作基本结束。
for(int i = 0;i< 4;i++)
{
//CvArr* s=(CvArr*)&result;
//cvLine(s,cvPointFrom32f(rectpoint[i]),cvPointFrom32f(rectpoint[(i+1)%4]),CV_G(0,0,255),2);
line(result,cvPointFrom32f(rectpoint[i]),cvPointFrom32f(rectpoint[(i+1)%4]),Scalar(125),2);
}
cvBoxPoints(End_Rage2D,rectpoint);
std::cout <<" angle:\n"<<(float)End_Rage2D.angle << std::endl; //被测物体旋转角度
}
cv::imshow("lalalal",result);
cv::waitKey();
return 0;
}
提取连通区域轮廓
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
// 移除过小或过大的轮廓
void getSizeContours(vector<vector<Point>> &contours)
{
int cmin = 100; // 最小轮廓长度
int cmax = 1000; // 最大轮廓长度
vector<vector<Point>>::const_iterator itc = contours.begin();
while(itc != contours.end())
{
if((itc->size()) < cmin || (itc->size()) > cmax)
{
itc = contours.erase(itc);
}
else ++ itc;
}
}
// 计算连通区域的轮廓,即二值图像中相连像素的形状
int main()
{
Mat image = imread("c:\\img\\1.bmp",0);
if(!image.data)
{
cout << "Fail to load image" << endl;
return 0;
}
Mat imageShold;
threshold(image, imageShold, 100, 255, THRESH_BINARY); // 必须进行二值化
vector<vector<Point>> contours;
//CV_CHAIN_APPROX_NONE 获取每个轮廓每个像素点
findContours(imageShold, contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, cvPoint(0,0));
getSizeContours(contours);
cout << contours.size() << endl;
Mat result(image.size(), CV_8U, Scalar(255));
drawContours(result, contours, -1, Scalar(0), 2); // -1 表示所有轮廓
namedWindow("result");
imshow("result", result);
namedWindow("image");
imshow("image", image);
waitKey(0);
return 0;
}
计算连通区域数目与最大连通区域并标示出
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
int main( int argc, char** argv )
{
IplImage* src = cvLoadImage("c:\\img\\1.png", CV_LOAD_IMAGE_GRAYSCALE);
IplImage* dst = cvCreateImage(cvGetSize(src), 8, 3);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contour = 0;
cvThreshold(src, src,120, 255, CV_THRESH_BINARY); // 二值化
cvNamedWindow("Source", 1);
cvShowImage("Source", src);
// 提取轮廓
int contour_num = cvFindContours(src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
cvZero(dst); // 清空数组
CvSeq *_contour = contour;
double maxarea = 0;
double minarea = 100;
int m = 0;
for( ; contour != 0; contour = contour->h_next )
{
double tmparea = fabs(cvContourArea(contour));
if(tmparea < minarea)
{
cvSeqRemove(contour, 0); // 删除面积小于设定值的轮廓
continue;
}
CvRect aRect = cvBoundingRect( contour, 0 );
if ((aRect.width/aRect.height)<1)
{
cvSeqRemove(contour, 0); //删除宽高比例小于设定值的轮廓
continue;
}
if(tmparea > maxarea)
{
maxarea = tmparea;
}
m++;
// 创建一个色彩值
CvScalar color = CV_RGB( 0, 255, 255 );
//max_level 绘制轮廓的最大等级。如果等级为0,绘制单独的轮廓。如果为1,绘制轮廓及在其后的相同的级别下轮廓
//如果值为2,所有的轮廓。如果等级为2,绘制所有同级轮廓及所有低一级轮廓,诸此种种
//如果值为负数,函数不绘制同级轮廓,但会升序绘制直到级别为abs(max_level)-1的子轮廓
cvDrawContours(dst, contour, color, color, -1, 1, 8); //绘制外部和内部的轮廓
}
contour = _contour;
int count = 0;
for(; contour != 0; contour = contour->h_next)
{
count++;
double tmparea = fabs(cvContourArea(contour));
if (tmparea == maxarea)
{
CvScalar color = CV_RGB( 255, 0, 0);
cvDrawContours(dst, contour, color, color, -1, 1, 8);
}
}
printf("The total number of contours is:%d", count);
cvNamedWindow("Components", 1);
cvShowImage("Components", dst);
cvWaitKey(0);
cvDestroyWindow("Source");
cvReleaseImage(&src);
cvDestroyWindow("Components");
cvReleaseImage(&dst);
return 0;
}
opencv 显示最小面积的外接矩形,并求该矩形的长和宽以及四个角的位置
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <math.h>
int main(int argc,char argv)
{
IplImage *src,*gray,*bw,*dst;
CvMemStorage* storage=cvCreateMemStorage(0);
CvSeq* contour=0;
char* filename= "c:\\img\\1.png";
if(!filename)
printf("can't open the file:%d\n",filename);
src=cvLoadImage(filename,1);
cvNamedWindow("image",1);
cvShowImage("image",src);
gray=cvCreateImage(cvSize(src->width,src->height),src->depth,1);
cvCvtColor(src,gray,CV_BGR2GRAY);
int hei,wid;
hei=gray->height;//注意此处是gray,otsu中要用到hei,wid,已在otsu.h中全局定义;
wid=gray->width;
printf("图像的高为:%d,宽为:%d\n\n",hei,wid);
cvNamedWindow("image2",1);
cvShowImage("image2",gray);
bw=cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
cvThreshold(gray,bw,128,255,CV_THRESH_BINARY_INV);
cvNamedWindow("image4",1);
cvShowImage("image4",bw);
dst=cvCloneImage(src);
cvFindContours(bw,storage,&contour,sizeof(CvContour),CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE);
for(;contour!=0;contour=contour->h_next)
{ CvBox2D rect=cvMinAreaRect2(contour,storage);
CvPoint2D32f rect_pts0[4];
cvBoxPoints(rect, rect_pts0);//在c++中已经被废除。
//因为cvPolyLine要求点集的输入类型是CvPoint
//所以要把 CvPoint2D32f 型的 rect_pts0 转换为 CvPoint 型的 rect_pts
//并赋予一个对应的指针 *pt
int npts = 4,k=0;
int aaa=0,bbb=0;
CvPoint rect_pts[4], *pt = rect_pts;
printf("连通区域最小外接矩形顶点坐标分别为:\n");
for (int i=0; i<4; i++)
{
rect_pts[i]= cvPointFrom32f(rect_pts0[i]);
printf("%d %d\n",rect_pts[i].x,rect_pts[i].y);
aaa=(int)sqrt((pow((float)(rect_pts[0].x-rect_pts[1].x),2)+pow((float)(rect_pts[0].y-rect_pts[1].y),2)));
bbb=(int)sqrt((pow((float)(rect_pts[0].x-rect_pts[3].x),2)+pow((float)(rect_pts[0].y-rect_pts[3].y),2)));
if(aaa<bbb)
{
k=aaa;
aaa=bbb;
bbb=k;
}
}
printf("最小外接矩形的长为:%d,宽为:%d。\n\n",aaa,bbb);
cvPolyLine(dst, &pt, &npts, 1, 1, CV_RGB(255,0,0), 1);
}
cvNamedWindow("image5",1);
cvShowImage("image5",dst);
cvWaitKey(0);//注意此句放的位置,放的不对则。。。
cvDestroyWindow("image");
cvDestroyWindow("image2");
cvDestroyWindow("image4");
cvDestroyWindow("image5");
cvReleaseImage(&src);
cvReleaseImage(&gray);
cvReleaseImage(&bw);
cvReleaseImage(&dst);
return 0;
}
数字分割
#include "stdafx.h"
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include "iostream"
#include <vector>
using namespace std;
CvRect CutTopButtom(IplImage *src);
vector<CvRect>leftright;
//vector<CvRect>::iterator iter;
int lstart=0,lend=0,lrun=0;
int lastStart=0,lastEnd=0;
IplImage *dst[10];
CvRect rectRoi;
void FindLeftRight(IplImage *src);
void RememberLeftRight(IplImage *src,int lstart,int lend);
void ShowAndCut(IplImage *src[]);
IplImage * raw=cvLoadImage("c:\\img\\3.bmp",0);
IplImage * img;
int _tmain(int argc, _TCHAR* argv[])
{
cvSmooth(raw,raw);
cvThreshold(raw,raw,70,255,CV_THRESH_BINARY);
IplConvKernel *element=0; //结构元素
cvMorphologyEx(raw,raw,NULL,element,CV_MOP_OPEN); //开运算
rectRoi=CutTopButtom(raw);
img=cvCreateImage(cvGetSize(raw),IPL_DEPTH_8U,1);
cvCopy(raw,img);
FindLeftRight(raw);
return 0;
}
CvRect CutTopButtom(IplImage *src)
{
int* h=new int[src->height];
memset(h,0,src->height*4);
int hstart,hend,x,y,zhongdian;
CvScalar s;
for(y=0;y<src->height;y++)
{
for(x=0;x<src->width;x++)
{
s=cvGet2D(src,y,x);
if(s.val[0]==0)
h[y]++;
}
}
for (int j=0;j!=src->height;j++)
{
if (h[j]>15)
{
zhongdian=j;
hstart=zhongdian;
break;
}
else
continue;
}
while(zhongdian!=src->height)
{
if (h[zhongdian]<10)
{
hend=zhongdian;
break;
}
else
hend=zhongdian;
zhongdian++;
}
CvRect rect=cvRect(0,hstart-10,src->width,hend-hstart+20);
cvSetImageROI(src,rect);
return rect;
}
void FindLeftRight(IplImage *src)
{
int* v=new int[rectRoi.width];
memset(v,0,rectRoi.width*4);
int x,y;
CvScalar s;
for(x=0;x<rectRoi.width;x++)
{
for(y=0;y<rectRoi.height;y++)
{
s=cvGet2D(src,y,x);
if(s.val[0]==0)
v[x]++;
else
continue;
}
}
if (lend<=rectRoi.width)
{
for (int i=0;i<rectRoi.width;i++)
{
if(v[i]>10)
{
lrun=i;
lstart=lrun;
break;
}
else
continue;
}
if (lstart==lrun)
{
for (lrun;lrun<rectRoi.width;lrun++)
{
if (v[lrun]<5)
{
lend=lrun;
break;
}
else
continue;
}
}
RememberLeftRight(src,lstart,lend);
}
else
ShowAndCut(dst);
}
void RememberLeftRight(IplImage *src,int lstart,int lend)
{
if (lastStart==0&&lastEnd==0)
{
lastStart=lastStart+lstart;
lastEnd=lastEnd+lend;
}
else
{
lastStart=lastEnd+lstart;
lastEnd=lastEnd+lend;
}
CvRect Rect=cvRect(lastStart-10,0,lastEnd-lastStart+20,rectRoi.height);
//CvRect Rect=cvRect(lastStart-5,0,lend-lstart+15,rectRoi.height);
leftright.push_back(Rect);
rectRoi=cvRect(lend,0,(rectRoi.width-lend),rectRoi.height);
cvSetImageROI(src,rectRoi);
FindLeftRight(src);
}
void ShowAndCut(IplImage *src[])
{
int i=0;
for (vector<CvRect>::iterator iter=leftright.begin();iter!=leftright.end();iter++,i++)
{
src[i]=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
cvCopy(img,src[i]);
cvSetImageROI(src[i],*iter);
cvNamedWindow("src");
cvShowImage("src",src[i]);
cvWaitKey(3000);
}
}