图像细化多用于机器人视觉,OCR字符识别等领域,细化后的图像经过去毛刺就成为了我们常说的图像的骨架。

 该图像细化代码依据论文: T. Y. ZHANG and C. Y. SUEN  A Fast Parallel Algorithm for Thinning Digital Patterns

代码如下:

void ThinSubiteration1(Mat & pSrc, Mat & pDst) {
int rows = pSrc.rows;
int cols = pSrc.cols;
pSrc.copyTo(pDst);
for(int i = ; i < rows; i++) {
for(int j = ; j < cols; j++) {
if(pSrc.at<float>(i, j) == 1.0f) {
/// get 8 neighbors
/// calculate C(p)
int neighbor0 = (int) pSrc.at<float>( i-, j-);
int neighbor1 = (int) pSrc.at<float>( i-, j);
int neighbor2 = (int) pSrc.at<float>( i-, j+);
int neighbor3 = (int) pSrc.at<float>( i, j+);
int neighbor4 = (int) pSrc.at<float>( i+, j+);
int neighbor5 = (int) pSrc.at<float>( i+, j);
int neighbor6 = (int) pSrc.at<float>( i+, j-);
int neighbor7 = (int) pSrc.at<float>( i, j-);
int C = int(~neighbor1 & ( neighbor2 | neighbor3)) +
int(~neighbor3 & ( neighbor4 | neighbor5)) +
int(~neighbor5 & ( neighbor6 | neighbor7)) +
int(~neighbor7 & ( neighbor0 | neighbor1));
if(C == ) {
/// calculate N
int N1 = int(neighbor0 | neighbor1) +
int(neighbor2 | neighbor3) +
int(neighbor4 | neighbor5) +
int(neighbor6 | neighbor7);
int N2 = int(neighbor1 | neighbor2) +
int(neighbor3 | neighbor4) +
int(neighbor5 | neighbor6) +
int(neighbor7 | neighbor0);
int N = min(N1,N2);
if ((N == ) || (N == )) {
/// calculate criteria 3
int c3 = ( neighbor1 | neighbor2 | ~neighbor4) & neighbor3;
if(c3 == ) {
pDst.at<float>( i, j) = 0.0f;
}
}
}
}
}
}
} void ThinSubiteration2(Mat & pSrc, Mat & pDst) {
int rows = pSrc.rows;
int cols = pSrc.cols;
pSrc.copyTo( pDst);
for(int i = ; i < rows; i++) {
for(int j = ; j < cols; j++) {
if (pSrc.at<float>( i, j) == 1.0f) {
/// get 8 neighbors
/// calculate C(p)
int neighbor0 = (int) pSrc.at<float>( i-, j-);
int neighbor1 = (int) pSrc.at<float>( i-, j);
int neighbor2 = (int) pSrc.at<float>( i-, j+);
int neighbor3 = (int) pSrc.at<float>( i, j+);
int neighbor4 = (int) pSrc.at<float>( i+, j+);
int neighbor5 = (int) pSrc.at<float>( i+, j);
int neighbor6 = (int) pSrc.at<float>( i+, j-);
int neighbor7 = (int) pSrc.at<float>( i, j-);
int C = int(~neighbor1 & ( neighbor2 | neighbor3)) +
int(~neighbor3 & ( neighbor4 | neighbor5)) +
int(~neighbor5 & ( neighbor6 | neighbor7)) +
int(~neighbor7 & ( neighbor0 | neighbor1));
if(C == ) {
/// calculate N
int N1 = int(neighbor0 | neighbor1) +
int(neighbor2 | neighbor3) +
int(neighbor4 | neighbor5) +
int(neighbor6 | neighbor7);
int N2 = int(neighbor1 | neighbor2) +
int(neighbor3 | neighbor4) +
int(neighbor5 | neighbor6) +
int(neighbor7 | neighbor0);
int N = min(N1,N2);
if((N == ) || (N == )) {
int E = (neighbor5 | neighbor6 | ~neighbor0) & neighbor7;
if(E == ) {
pDst.at<float>(i, j) = 0.0f;
}
}
}
}
}
}
}
int main(int argc, char* argv[])
{
Mat src = imread("D://thinning.png", );
Mat inputarray = src(Rect(, , src.cols - , src.rows - ));
threshold(inputarray, inputarray, , , CV_THRESH_BINARY);
Mat outputarray(inputarray.rows,inputarray.cols,CV_32FC1); bool bDone = false;
int rows = inputarray.rows;
int cols = inputarray.cols; inputarray.convertTo(inputarray, CV_32FC1); inputarray.copyTo(outputarray); //outputarray.convertTo(outputarray, CV_32FC1); /// pad source
Mat p_enlarged_src = Mat(rows + , cols + , CV_32FC1);
for (int i = ; i < (rows + ); i++) {
p_enlarged_src.at<float>(i, ) = 0.0f;
p_enlarged_src.at<float>(i, cols + ) = 0.0f;
}
for (int j = ; j < (cols + ); j++) {
p_enlarged_src.at<float>(, j) = 0.0f;
p_enlarged_src.at<float>(rows + , j) = 0.0f;
}
for (int i = ; i < rows; i++) {
for (int j = ; j < cols; j++) {
if (inputarray.at<float>(i, j) >= 20.0f) {
p_enlarged_src.at<float>(i + , j + ) = 1.0f;
}
else
p_enlarged_src.at<float>(i + , j + ) = 0.0f;
}
} /// start to thin
Mat p_thinMat1 = Mat::zeros(rows + , cols + , CV_32FC1);
Mat p_thinMat2 = Mat::zeros(rows + , cols + , CV_32FC1);
Mat p_cmp = Mat::zeros(rows + , cols + , CV_8UC1); while (bDone != true) {
/// sub-iteration 1
ThinSubiteration1(p_enlarged_src, p_thinMat1);
/// sub-iteration 2
//ThinSubiteration2(p_thinMat1, p_thinMat2);
/// compare
compare(p_enlarged_src, p_thinMat1, p_cmp, CV_CMP_EQ);
/// check
int num_non_zero = countNonZero(p_cmp);
if (num_non_zero == (rows + ) * (cols + )) {
bDone = true;
}
/// copy
p_thinMat1.copyTo(p_enlarged_src);
}
// copy result
for (int i = ; i < rows; i++) {
for (int j = ; j < cols; j++) {
outputarray.at<float>(i, j) = p_enlarged_src.at<float>(i + , j + );
}
}
imshow("src", inputarray);
imshow("dst", p_enlarged_src);
waitKey(); return ; }

附上效果图:

未完待续。。。。

opencv 图像细化的更多相关文章

  1. OpenCV图像细化的一个例子

    转自:http://blog.csdn.net/zfdxx369/article/details/9091953?utm_source=tuicool 本文是zhang的一篇经典图像细化论文,效果很好 ...

  2. 【opencv】图像细化

    [原文:http://blog.csdn.net/qianchenglenger/article/details/19332011] 在我们进行图像处理的时候,有可能需要对图像进行细化,提取出图像的骨 ...

  3. SSE图像算法优化系列三十二:Zhang\Guo图像细化算法的C语言以及SIMD指令优化

    二值图像的细化算法也有很多种,比较有名的比如Hilditch细化.Rosenfeld细化.基于索引表的细化.还有Opencv自带的THINNING_ZHANGSUEN.THINNING_GUOHALL ...

  4. OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

    这篇已经写得很好,真心给作者点个赞.题目都是直接转过来的,直接去看吧. Reference Link : http://blog.csdn.net/poem_qianmo/article/detail ...

  5. 【OpenCV新手教程之十三】OpenCV图像金字塔:高斯金字塔、拉普拉斯金字塔与图片尺寸缩放

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/26157633 作者:毛星云(浅墨) ...

  6. Opencv 图像叠加 添加水印

    Opencv 图像叠加 添加水印 C++: void Mat::copyTo(OutputArray m) const C++: void Mat::copyTo(OutputArray m, Inp ...

  7. opencv图像读取-imread

    前言 图像的读取和保存一定要注意imread函数的各个参数及其意义,尽量不要使用默认参数,否则就像数据格式出现错误(here)一样,很难查找错误原因的: re: 1.opencv图像的读取与保存; 完

  8. 学习 opencv---(12)OpenCV 图像金字塔:高斯金字塔,拉普拉斯金字塔与图片尺寸缩放

    在这篇文章里,我们一起学习下 图像金字塔 的一些基本概念,如何使用OpenCV函数pyrUp和pyrDown 对图像进行向上和向下采样,以及了解专门用于缩放图像尺寸的resize函数的用法.此博文一共 ...

  9. [OpenCV Qt教程] 在Qt图形界面中显示OpenCV图像的OpenGL Widget(第二部分)

    本文译自:http://www.robot-home.it/blog/en/software/tutorial-opencv-qt-opengl-widget-per-visualizzare-imm ...

随机推荐

  1. P4363 [九省联考2018]一双木棋

    题面 这种搜索要把后继状态都跑出来之后取Min/Max 也就是回溯的时候进行操作 记得用hash进行记忆化(用map不开O2会TLE) #include<iostream> #includ ...

  2. mac 密码重置

    首先请开机或重新启动系统,在电脑刚启动时,请按下键盘上的 command+S 组合键不动, 接下来会在屏幕上看到一串串的命令字符显示,当进入安全模式以后,会看到 一个 root 开始的命令行输入端口. ...

  3. springboot中的mybatis是如果使用pagehelper的

    springboot中使用其他组件都是基于自动配置的AutoConfiguration配置累的,pagehelper插件也是一样的,通过PageHelperAutoConfiguration的,这个类 ...

  4. Linux入门命令

    ####常用的目录 /主目录 ① /root:存放启动Linux时启动的核心文件,包括一些连接文件以及镜像 ② /bin:binary的缩写,存放经常使用的命令 ③ /dev:Device(设备)的缩 ...

  5. KiCAD泪滴

    KiCAD泪滴 KiCAD没有自带的补泪滴功能,必须先下载一个插件,然后才能进行泪滴操作 链接 提取码:ey8o 1.下载泪滴插件,解压后将整个文件夹复制到目录  C:\Program Files\K ...

  6. javascript onclick事件可以调用两个方法吗?

    答案是:可以的,onclick事件可以调用多个方法,每个方法之间用分号(:)隔开即可. onclick后面其实是可以写任何代码的,但是一般不建议这么写!! 例:onclick="fun1() ...

  7. Mysql学习笔记(004)- 条件查询

    条件查询 #进阶2:条件查询 /* 语法: select 查询列表③ from 表名① where 条件筛选② 分类: 一.按条件表达式筛选 条件运算符:> < = != <> ...

  8. 深入理解Magento - 第一章 - Magento强大的配置系统

    深入理解Magento 作者:Alan Storm翻译:zhlmmc 前言第一章 - Magento强大的配置系统第二章 - Magento请求分发与控制器第三章 - 布局,块和模板第四章 - 模型和 ...

  9. 在SpringCloud中MAVEN配置文件中的更改

    <mirrors> <mirror> <id>alimaven</id> <mirrorOf>central</mirrorOf> ...

  10. iphone5越狱后问题的解决办法

    1,添加各种源失败,显示红字. 解决办法: 如果出现bad 404等红字,一般是由于网络问题,服务器挤爆了,导致不能添加,这种情况大家可以换一个时间段添加源,或者使用网速快一点的网络,比如3g,多试几 ...