選擇輪廓(select_shape)
Halcon是一款運用廣泛的圖像識別和處理軟件。在膚淺的接觸中,它的輪廓選擇算子(select_shape)給予我很深的印象。結果是往往幾行代碼就能夠產生很好的效果:
比如要得到這樣的結果

只需要
read_image (Image1,
'F:/未來項目/鋼管識別/FindTube/FindTube/1.jpg')
rgb1_to_gray (Image1, GrayImage)
threshold (GrayImage, Regions, 43, 111)
connection (Regions, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 150, 666)
select_shape (SelectedRegions, SelectedRegions1, 'circularity', 'and', 0. 45, 1)
rgb1_to_gray (Image1, GrayImage)
threshold (GrayImage, Regions, 43, 111)
connection (Regions, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 150, 666)
select_shape (SelectedRegions, SelectedRegions1, 'circularity', 'and', 0. 45, 1)
當然Halcon是在背后做了許多工作的。
幾行代碼中,比較重要的是算子就是"select_shape"。這個算子的參數很多,我也就比較熟悉這兩種。
如果我想在Opencv中也要這樣的結果,就需要自己動手嘗試實現。實現過程中我采用了類似的函數名表示敬意。
// selectshape.cpp : 選擇輪廓
// by: jsxyhelu(1755311380)
# include "stdafx.h"
# include <iostream >
# include "opencv2/core/core.hpp"
# include "opencv2/highgui/highgui.hpp"
# include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
# define VP vector <Point > //用VP符號代替 vector<point>
RNG rng( 12345 );
//帶有上下限的threshold
void threshold2(Mat gray,Mat & thresh, int minvalue, int maxvalue)
{
Mat thresh1;
Mat thresh2;
threshold(gray,thresh1, 43, 255, THRESH_BINARY);
threshold(gray,thresh2, 111, 255,THRESH_BINARY_INV);
thresh = thresh1 & thresh2;
}
//尋找並繪制出聯通區域
vector <VP > connection2(Mat src,Mat & draw)
{
draw = Mat : :zeros(src.rows,src.cols,CV_8UC3);
vector <VP >contours;
findContours(src,contours,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
for ( int i = 0;i <contours.size();i ++)
{
Scalar color = Scalar(rng.uniform( 0, 255),rng.uniform( 0, 255),rng.uniform( 0, 255));
drawContours(draw,contours,i,color, - 1);
}
return contours;
}
//select_shape
vector <VP > selectShapeArea(Mat src,Mat & draw,vector <VP > contours, int minvalue, int maxvalue)
{
vector <VP > result_contours;
draw = Mat : :zeros(src.rows,src.cols,CV_8UC3);
for ( int i = 0;i <contours.size();i ++)
{
int countour_area = contourArea(contours[i]);
if (countour_area >minvalue && countour_area <maxvalue)
{
result_contours.push_back(contours[i]);
}
}
for ( int i = 0;i <result_contours.size();i ++)
{
Scalar color = Scalar(rng.uniform( 0, 255),rng.uniform( 0, 255),rng.uniform( 0, 255));
drawContours(draw,result_contours,i,color, - 1);
}
return result_contours;
}
//計算輪廓的圓的特性
float calculateCircularity(VP contour)
{
Point2f center;
float radius = 0;
minEnclosingCircle((Mat)contour,center,radius);
//以最小外接圓半徑作為數學期望,計算輪廓上各點到圓心距離的標准差
float fsum = 0;
float fcompare = 0;
for ( int i = 0;i <contour.size();i ++)
{
Point2f ptmp = contour[i];
float fdistenct = sqrt(( float)((ptmp.x - center.x) *(ptmp.x - center.x) +(ptmp.y - center.y) *(ptmp.y -center.y)));
float fdiff = abs(fdistenct - radius);
fsum = fsum + fdiff;
}
fcompare = fsum /( float)contour.size();
return fcompare;
}
//select_shape
vector <VP > selectShapeCircularity(Mat src,Mat & draw,vector <VP > contours, float minvalue, float maxvalue)
{
vector <VP > result_contours;
draw = Mat : :zeros(src.rows,src.cols,CV_8UC3);
for ( int i = 0;i <contours.size();i ++)
{
float fcompare = calculateCircularity(contours[i]);
if (fcompare > =minvalue && fcompare < =maxvalue)
{
result_contours.push_back(contours[i]);
}
}
for ( int i = 0;i <result_contours.size();i ++)
{
Scalar color = Scalar(rng.uniform( 0, 255),rng.uniform( 0, 255),rng.uniform( 0, 255));
drawContours(draw,result_contours,i,color, - 1);
}
return result_contours;
}
int _tmain( int argc, _TCHAR * argv[])
{
Mat src;
Mat gray;
Mat thresh;
Mat draw_connection;
Mat draw_area;
Mat draw_circle;
vector <VP >contours_connection;
vector <VP >contours_area;
vector <VP >contours_circle;
vector <VP >contours_tmp;
//read_image (Image1, 'F:/未來項目/鋼管識別/FindTube/FindTube/1.jpg')
src = imread( "1.jpg");
//rgb1_to_gray (Image1, GrayImage)
cvtColor(src,gray,COLOR_BGR2GRAY);
//threshold (GrayImage, Regions, 43, 111)
threshold2(gray,thresh, 43, 111);
//connection (Regions, ConnectedRegions)
contours_connection = connection2(thresh.clone(),draw_connection);
//select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 150, 666)
contours_area = selectShapeArea(thresh.clone(),draw_area,contours_connection, 150, 666);
//select_shape (SelectedRegions, SelectedRegions1, 'circularity', 'and', 0.45, 1)
contours_circle = selectShapeCircularity(thresh.clone(),draw_circle,contours_area, 1, 6);
//顯示結果
imshow( "src",src);
imshow( "thresh",thresh);
imshow( "draw_connection",draw_connection);
imshow( "draw_area",draw_area);
imshow( "draw_circle",draw_circle);
waitKey();
}
// by: jsxyhelu(1755311380)
# include "stdafx.h"
# include <iostream >
# include "opencv2/core/core.hpp"
# include "opencv2/highgui/highgui.hpp"
# include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;
# define VP vector <Point > //用VP符號代替 vector<point>
RNG rng( 12345 );
//帶有上下限的threshold
void threshold2(Mat gray,Mat & thresh, int minvalue, int maxvalue)
{
Mat thresh1;
Mat thresh2;
threshold(gray,thresh1, 43, 255, THRESH_BINARY);
threshold(gray,thresh2, 111, 255,THRESH_BINARY_INV);
thresh = thresh1 & thresh2;
}
//尋找並繪制出聯通區域
vector <VP > connection2(Mat src,Mat & draw)
{
draw = Mat : :zeros(src.rows,src.cols,CV_8UC3);
vector <VP >contours;
findContours(src,contours,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
for ( int i = 0;i <contours.size();i ++)
{
Scalar color = Scalar(rng.uniform( 0, 255),rng.uniform( 0, 255),rng.uniform( 0, 255));
drawContours(draw,contours,i,color, - 1);
}
return contours;
}
//select_shape
vector <VP > selectShapeArea(Mat src,Mat & draw,vector <VP > contours, int minvalue, int maxvalue)
{
vector <VP > result_contours;
draw = Mat : :zeros(src.rows,src.cols,CV_8UC3);
for ( int i = 0;i <contours.size();i ++)
{
int countour_area = contourArea(contours[i]);
if (countour_area >minvalue && countour_area <maxvalue)
{
result_contours.push_back(contours[i]);
}
}
for ( int i = 0;i <result_contours.size();i ++)
{
Scalar color = Scalar(rng.uniform( 0, 255),rng.uniform( 0, 255),rng.uniform( 0, 255));
drawContours(draw,result_contours,i,color, - 1);
}
return result_contours;
}
//計算輪廓的圓的特性
float calculateCircularity(VP contour)
{
Point2f center;
float radius = 0;
minEnclosingCircle((Mat)contour,center,radius);
//以最小外接圓半徑作為數學期望,計算輪廓上各點到圓心距離的標准差
float fsum = 0;
float fcompare = 0;
for ( int i = 0;i <contour.size();i ++)
{
Point2f ptmp = contour[i];
float fdistenct = sqrt(( float)((ptmp.x - center.x) *(ptmp.x - center.x) +(ptmp.y - center.y) *(ptmp.y -center.y)));
float fdiff = abs(fdistenct - radius);
fsum = fsum + fdiff;
}
fcompare = fsum /( float)contour.size();
return fcompare;
}
//select_shape
vector <VP > selectShapeCircularity(Mat src,Mat & draw,vector <VP > contours, float minvalue, float maxvalue)
{
vector <VP > result_contours;
draw = Mat : :zeros(src.rows,src.cols,CV_8UC3);
for ( int i = 0;i <contours.size();i ++)
{
float fcompare = calculateCircularity(contours[i]);
if (fcompare > =minvalue && fcompare < =maxvalue)
{
result_contours.push_back(contours[i]);
}
}
for ( int i = 0;i <result_contours.size();i ++)
{
Scalar color = Scalar(rng.uniform( 0, 255),rng.uniform( 0, 255),rng.uniform( 0, 255));
drawContours(draw,result_contours,i,color, - 1);
}
return result_contours;
}
int _tmain( int argc, _TCHAR * argv[])
{
Mat src;
Mat gray;
Mat thresh;
Mat draw_connection;
Mat draw_area;
Mat draw_circle;
vector <VP >contours_connection;
vector <VP >contours_area;
vector <VP >contours_circle;
vector <VP >contours_tmp;
//read_image (Image1, 'F:/未來項目/鋼管識別/FindTube/FindTube/1.jpg')
src = imread( "1.jpg");
//rgb1_to_gray (Image1, GrayImage)
cvtColor(src,gray,COLOR_BGR2GRAY);
//threshold (GrayImage, Regions, 43, 111)
threshold2(gray,thresh, 43, 111);
//connection (Regions, ConnectedRegions)
contours_connection = connection2(thresh.clone(),draw_connection);
//select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 150, 666)
contours_area = selectShapeArea(thresh.clone(),draw_area,contours_connection, 150, 666);
//select_shape (SelectedRegions, SelectedRegions1, 'circularity', 'and', 0.45, 1)
contours_circle = selectShapeCircularity(thresh.clone(),draw_circle,contours_area, 1, 6);
//顯示結果
imshow( "src",src);
imshow( "thresh",thresh);
imshow( "draw_connection",draw_connection);
imshow( "draw_area",draw_area);
imshow( "draw_circle",draw_circle);
waitKey();
}
結果如下,這段代碼中還有一個問題,就是計算輪廓圓的性質的方法,我這里采用的是自己想出來的方法,似乎不是很完善,需要進一步找到資料才修正。
