参考文章:
A Fast parallel algorithm for thinning digital patternshttps://dl.acm.org/doi/pdf/10.1145/357994.358023【opencv】图像细化
https://blog.csdn.net/qianchenglenger/article/details/19332011Windows 下使用了自带的并行库ppl,跨平台的话使用 tbb 也是可以无痛切换的。参考了https://blog.csdn.net/qianchenglenger/article/details/19332011 的文章,进行了边界和并行优化。
#include <opencv2/core/core.hpp>
#include <iostream>
#include <vector>
#include <ppl.h>
/*
* 参考论文:A Fast parallel algorithm for thinning digital patterns
* 论文出处:https://dl.acm.org/doi/pdf/10.1145/357994.358023
*/
cv::Mat ThinImage(const cv::Mat& src)
{
assert(src.type() == CV_8UC1);
cv::Mat dst;
const int width = src.cols - 1;
const int height = src.rows - 1;
src.copyTo(dst);
while (true)
{
std::vector<std::vector<uchar*>> mFlags;
auto work = [&](const int index)
{
mFlags.resize(height);
Concurrency::parallel_for(1, height, [&](int i)
{
std::vector<uchar*> local_flag;
uchar* p = dst.ptr<uchar>(i);
for (int j = 1; j < width; ++j)
{
// 进行8邻域标记
const uchar p1 = p[j];
if (p1 != 1) continue;
const uchar p4 = *(p + j + 1);
const uchar p8 = *(p + j - 1);
const uchar p2 = *(p - dst.step + j);
const uchar p3 = *(p - dst.step + j + 1);
const uchar p9 = *(p - dst.step + j - 1);
const uchar p6 = *(p + dst.step + j);
const uchar p5 = *(p + dst.step + j + 1);
const uchar p7 = *(p + dst.step + j - 1);
if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6)
{
int ap = 0;
if (p2 == 0 && p3 == 1) ++ap;
if (p3 == 0 && p4 == 1) ++ap;
if (p4 == 0 && p5 == 1) ++ap;
if (p5 == 0 && p6 == 1) ++ap;
if (p6 == 0 && p7 == 1) ++ap;
if (p7 == 0 && p8 == 1) ++ap;
if (p8 == 0 && p9 == 1) ++ap;
if (p9 == 0 && p2 == 1) ++ap;
bool flag = false;
switch (index)
{
case 0:
flag = ap == 1 && p2 * p4 * p6 == 0 && p4 * p6 * p8 == 0;
break;
case 1:
flag = ap == 1 && p2 * p4 * p8 == 0 && p2 * p6 * p8 == 0;
break;
default:
break;
}
if (flag)
{
//暂存标记点
local_flag.push_back(p + j);
}
}
}
mFlags[i] = local_flag;
});
//删除标记点
for (auto it = mFlags.begin(); it != mFlags.end(); ++it)
{
auto& local = (*it);
for (auto it_local = local.begin(); it_local != local.end(); ++it_local) {
**it_local = 0;
}
}
int finish = 0;
for (auto it = mFlags.begin(); it != mFlags.end(); ++it)
{
finish += it->empty();
}
if (finish == height)
{
return true;
}
else {
mFlags.clear();
return false;
}
};
if (work(0))
return dst;
if (work(1))
return dst;
}
}