因为在opencv100wen后续没有看到C++解答,这题按原本的思路自己写了,但图像细化的有问题变得像梳子一样,参考了一些发现判断条件都有所区别。
大致思路如下:(分了3段)
从左上角开始光栅扫描
如果(x,y)=0不处理,为1,满足下面五个条件时设-1
a.4-近邻像素的取值有一个以上为0
b.8-连接数为1,即端点
c.8-近邻的绝对值之和大于2
d.8-近邻中有1个以上取值为1 (这个条件在函数中去掉了)
e. 对所有8个近邻点xn满足任意一个(xn值不为-1 || 当xn值为0时(x,y)的8-连接数为1)
将每个像素的-1更改为0
重复光栅扫描,直到步骤3中像素值改变次数为0
Mat hilditch(Mat otsu) {
int height = otsu.rows;
int width = otsu.cols;
Mat out = otsu.clone();
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
if (out.at<uchar>(y, x) == 255)
out.at<uchar>(y, x) = 1;
}
}
int count = 1;
while (count > 0) {
count = 0;
Mat tmp = out.clone();
Mat tmp8 = out.clone();
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
tmp8.at<uchar>(y, x) = 1 - tmp8.at<uchar>(y, x); //8-连接数
}
}
Mat _tmp8 = tmp8.clone();
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
if (tmp.at<uchar>(y, x) == 0) //背景为0黑底,跳过
continue;
int judge = 0;
//condition 1: 4-近邻像素的取值有一个以上为0
if (tmp.at<uchar>(y, min(x + 1, width - 1)) * tmp.at<uchar>(y, max(x - 1, 0))
* tmp.at<uchar>(min(y + 1, height - 1), x) * tmp.at<uchar>(max(y - 1, 0), x) == 0)
++judge;
//condition 2: 8-连接数为1
int S = 0;
S += tmp8.at<uchar>(y, min(x + 1, width - 1)) - tmp8.at<uchar>(y, min(x + 1, width - 1))
*tmp8.at<uchar>(max(y - 1, 0), min(x + 1, width - 1))*tmp8.at<uchar>(max(y - 1, 0), x);
S += tmp8.at<uchar>(max(y - 1, 0), x) - tmp8.at<uchar>(max(y - 1, 0), x)
*tmp8.at<uchar>(max(y - 1, 0), max(x - 1, 0))*tmp8.at<uchar>(y, max(x - 1, 0));
S += tmp8.at<uchar>(y, max(x - 1, 0)) - tmp8.at<uchar>(y, max(x - 1, 0))
*tmp8.at<uchar>(min(y + 1, height - 1), max(x - 1, 0))*tmp8.at<uchar>(min(y + 1, height - 1), x);
S += tmp8.at<uchar>(min(y + 1, height - 1), x) - tmp8.at<uchar>(min(y + 1, height - 1), x)
*tmp8.at<uchar>(min(y + 1, height - 1), min(x + 1, width - 1))*tmp8.at<uchar>(y, min(x + 1, width - 1));
if (S == 1)
++judge;
//condition 3: 8-近邻的绝对值之和大于2 tmp只有0 1所以不用abs 这里在其他博客看到有>=根据这张图没啥区别,回头再验证,我想如果正好是对称位置的两点那就不那被标记为背景
if (tmp.at<uchar>(y, min(x + 1, width - 1)) + tmp.at<uchar>(y, max(x - 1, 0))
+ tmp.at<uchar>(min(y + 1, height - 1), x) + tmp.at<uchar>(max(y - 1, 0), x)
+ tmp.at<uchar>(max(y - 1, 0), min(x + 1, width - 1)) + tmp.at<uchar>(max(y - 1, 0), max(x - 1, 0))
+ tmp.at<uchar>(min(y + 1, height - 1), max(x - 1, 0)) + tmp.at<uchar>(min(y + 1, height - 1), min(x + 1, width - 1)) > 2)
++judge;
//condition 4: 8-近邻中有1个以上取值为1 把条件4去掉得出的结果就比较优秀了
/*
int condition4 = 0;
for (int dy = -1; dy < 2; ++dy) {
for (int dx = -1; dx < 2; ++dx) {
if (dy == 0 && dx == 0)
continue;
else if (out.at(min(max(y + dy, 0), height - 1), min(max(x + dx, 0), width - 1)) == 1)
++condition4;
if (condition4 > 1) {
++judge;
break;
}
}
if (judge == 4)
break;
}*/
if (judge < 3)//条件不满足可以直接下一个点
continue;
//condition 5: 对所有8个近邻点xn满足任意一个
// xn值不为 - 1 || 当xn值为0时,x连接数为1(但没有判断值为0,判断了有问题)
//重新计算8-连接数
for (int dy = -1; dy < 2; ++dy) {
for (int dx = -1; dx < 2; ++dx) {
_tmp8.at<uchar>(min(max(y + dy, 0), height - 1), min(max(x + dx, 0), width - 1)) = 1 - out.at<uchar>(min(max(y + dy, 0), height - 1), min(max(x + dx, 0), width - 1));
}
}
S = 0;
S += _tmp8.at<uchar>(y, min(x + 1, width - 1)) - _tmp8.at<uchar>(y, min(x + 1, width - 1))
*_tmp8.at<uchar>(max(y - 1, 0), min(x + 1, width - 1))*_tmp8.at<uchar>(max(y - 1, 0), x);
S += _tmp8.at<uchar>(max(y - 1, 0), x) - _tmp8.at<uchar>(max(y - 1, 0), x)
*_tmp8.at<uchar>(max(y - 1, 0), max(x - 1, 0))*_tmp8.at<uchar>(y, max(x - 1, 0));
S += _tmp8.at<uchar>(y, max(x - 1, 0)) - _tmp8.at<uchar>(y, max(x - 1, 0))
*_tmp8.at<uchar>(min(y + 1, height - 1), max(x - 1, 0))*_tmp8.at<uchar>(min(y + 1, height - 1), x);
S += _tmp8.at<uchar>(min(y + 1, height - 1), x) - _tmp8.at<uchar>(min(y + 1, height - 1), x)
*_tmp8.at<uchar>(min(y + 1, height - 1), min(x + 1, width - 1))*_tmp8.at<uchar>(y, min(x + 1, width - 1));
//leftup
if (S == 1 || tmp.at<uchar>(max(y - 1, 0), max(x - 1, 0)) != out.at<uchar>(max(y - 1, 0), max(x - 1, 0)))
++judge;
//up
if (S == 1 || tmp.at<uchar>(max(y - 1, 0), x) != out.at<uchar>(max(y - 1, 0), x))
++judge;
//rightup
if (S == 1 || tmp.at<uchar>(max(y - 1, 0), min(x + 1, width - 1)) != out.at<uchar>(max(y - 1, 0), min(x + 1, width - 1)))
++judge;
//left
if (S == 1 || tmp.at<uchar>(y, max(x - 1, 0)) != out.at<uchar>(y, max(x - 1, 0)))
++judge;
if (judge == 7) {
out.at<uchar>(y, x) = 0; //-1但是负数转为255后面还给0,就直接给0
++count;
}
}
}
}
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
if (out.at<uchar>(y, x) == 1)
out.at<uchar>(y, x) = 255;
}
}
return out;
}