一. 读取图像
CommandLineParser parser(argc, argv, keys);
help();
if (parser.has("help"))
return 0;
string filename = parser.get<string>(0);
gray = imread(filename, 0);
if(gray.empty())
{
printf("Cannot read image file: %s\n", filename.c_str());
help();
return -1;
}
namedWindow("Distance Map", 1);
createTrackbar("Brightness Threshold", "Distance Map", &edgeThresh, 255, onTrackbar, 0);
二. 核心算法
static void onTrackbar( int, void* )
{
static const Scalar colors[] =
{
Scalar(0,0,0),
Scalar(255,0,0),
Scalar(255,128,0),
Scalar(255,255,0),
Scalar(0,255,0),
Scalar(0,128,255),
Scalar(0,255,255),
Scalar(0,0,255),
Scalar(255,0,255)
};
int maskSize = voronoiType >= 0 ? DIST_MASK_5 : maskSize0;
int distType = voronoiType >= 0 ? DIST_L2 : distType0;
Mat edge = gray >= edgeThresh, dist, labels, dist8u;
if( voronoiType < 0 )
distanceTransform( edge, dist, distType, maskSize );//任意点到最近背景点的距离
else
distanceTransform( edge, dist, labels, distType, maskSize, voronoiType );
if( voronoiType < 0 )
{
// begin "painting" the distance transform result
dist *= 5000;
pow(dist, 0.5, dist);
Mat dist32s, dist8u1, dist8u2;
dist.convertTo(dist32s, CV_32S, 1, 0.5);
dist32s &= Scalar::all(255);
dist32s.convertTo(dist8u1, CV_8U, 1, 0);
dist32s *= -1;
dist32s += Scalar::all(255);
dist32s.convertTo(dist8u2, CV_8U);
Mat planes[] = {dist8u1, dist8u2, dist8u2};
merge(planes, 3, dist8u);
}
else
{
dist8u.create(labels.size(), CV_8UC3);
for( int i = 0; i < labels.rows; i++ )
{
const int* ll = (const int*)labels.ptr(i);
const float* dd = (const float*)dist.ptr(i);
uchar* d = (uchar*)dist8u.ptr(i);
for( int j = 0; j < labels.cols; j++ )
{
int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1;
float scale = 1.f/(1 + dd[j]*dd[j]*0.0004f);
int b = cvRound(colors[idx][0]*scale);
int g = cvRound(colors[idx][1]*scale);
int r = cvRound(colors[idx][2]*scale);
d[j*3] = (uchar)b;
d[j*3+1] = (uchar)g;
d[j*3+2] = (uchar)r;
}
}
}
imshow("Distance Map", dist8u );
}(1)二值化
(2)调用 distanceTransform函数
(3)根据distanceTransform函数计算结果,绘制距离变换图像(图像的值表示距离)
三.键盘控制
for(;;)
{
// Call to update the view
onTrackbar(0, 0);
char c = (char)waitKey(0);
if( c == 27 )
break;
if( c == 'c' || c == 'C' || c == '1' || c == '2' ||
c == '3' || c == '5' || c == '0' )
voronoiType = -1;
if( c == 'c' || c == 'C' )
distType0 = DIST_C;
else if( c == '1' )
distType0 = DIST_L1;
else if( c == '2' )
distType0 = DIST_L2;
else if( c == '3' )
maskSize0 = DIST_MASK_3;
else if( c == '5' )
maskSize0 = DIST_MASK_5;
else if( c == '0' )
maskSize0 = DIST_MASK_PRECISE;
else if( c == 'v' )
voronoiType = 0;
else if( c == 'p' )
voronoiType = 1;
else if( c == ' ' )
{
if( voronoiType == 0 )
voronoiType = 1;
else if( voronoiType == 1 )
{
voronoiType = -1;
maskSize0 = DIST_MASK_3;
distType0 = DIST_C;
}
else if( distType0 == DIST_C )
distType0 = DIST_L1;
else if( distType0 == DIST_L1 )
distType0 = DIST_L2;
else if( maskSize0 == DIST_MASK_3 )
maskSize0 = DIST_MASK_5;
else if( maskSize0 == DIST_MASK_5 )
maskSize0 = DIST_MASK_PRECISE;
else if( maskSize0 == DIST_MASK_PRECISE )
voronoiType = 0;
}
}
四. 分割效果
