图像细化
?在我們進行圖像處理的時候,有可能需要對圖像進行細化,提取出圖像的骨架信息,進行更加有效的分析。
???? 圖像細化(Image Thinning),一般指二值圖像的骨架化(Image Skeletonization) 的一種操作運算。
???? 所謂的細化就是經過一層層的剝離,從原來的圖中去掉一些點,但仍要保持原來的形狀,直到得到圖像的骨架。骨架,可以理解為圖象的中軸。
???? 好的細化算法一定要滿足:- 收斂性;
- 保證細化后細線的連通性;
- 保持原圖的基本形狀;
- 減少筆畫相交處的畸變;
- 細化結果是原圖像的中心線;
- 細化的快速性和迭代次數少;
????這里,我們對“Zhang并行快速細化算法”進行了實現(注意,該算法為并行算法,而我們在實現過程中并沒有并行化處理,所以,效率并沒有達到最好)。
????參考資料
- 細化算法
- 論文 A fast parallel algorithm for thinning digital patterns [cpp]?view plaincopy
- #include?<opencv2/opencv.hpp>??
- #include?<opencv2/core/core.hpp>??
- #include?<iostream>??
- #include?<vector>??
- ??
- ??
- /**?
- ?*?@brief?對輸入圖像進行細化?
- ?*?@param?src為輸入圖像,用cvThreshold函數處理過的8位灰度圖像格式,元素中只有0與1,1代表有元素,0代表為空白?
- ?*?@param?maxIterations限制迭代次數,如果不進行限制,默認為-1,代表不限制迭代次數,直到獲得最終結果?
- ?*?@return?為對src細化后的輸出圖像,格式與src格式相同,元素中只有0與1,1代表有元素,0代表為空白?
- ?*/??
- cv::Mat?thinImage(const?cv::Mat?&?src,?const?int?maxIterations?=?-1)??
- {??
- ????assert(src.type()?==?CV_8UC1);??
- ????cv::Mat?dst;??
- ????int?width??=?src.cols;??
- ????int?height?=?src.rows;??
- ????src.copyTo(dst);??
- ????int?count?=?0;??//記錄迭代次數??
- ????while?(true)??
- ????{??
- ????????count++;??
- ????????if?(maxIterations?!=?-1?&&?count?>?maxIterations)?//限制次數并且迭代次數到達??
- ????????????break;??
- ????????std::vector<uchar?*>?mFlag;?//用于標記需要刪除的點??
- ????????//對點標記??
- ????????for?(int?i?=?0;?i?<?height?;++i)??
- ????????{??
- ????????????uchar?*?p?=?dst.ptr<uchar>(i);??
- ????????????for?(int?j?=?0;?j?<?width;?++j)??
- ????????????{??
- ????????????????//如果滿足四個條件,進行標記??
- ????????????????//??p9?p2?p3??
- ????????????????//??p8?p1?p4??
- ????????????????//??p7?p6?p5??
- ????????????????uchar?p1?=?p[j];??
- ????????????????if?(p1?!=?1)?continue;??
- ????????????????uchar?p4?=?(j?==?width?-?1)???0?:?*(p?+?j?+?1);??
- ????????????????uchar?p8?=?(j?==?0)???0?:?*(p?+?j?-?1);??
- ????????????????uchar?p2?=?(i?==?0)???0?:?*(p?-?dst.step?+?j);??
- ????????????????uchar?p3?=?(i?==?0?||?j?==?width?-?1)???0?:?*(p?-?dst.step?+?j?+?1);??
- ????????????????uchar?p9?=?(i?==?0?||?j?==?0)???0?:?*(p?-?dst.step?+?j?-?1);??
- ????????????????uchar?p6?=?(i?==?height?-?1)???0?:?*(p?+?dst.step?+?j);??
- ????????????????uchar?p5?=?(i?==?height?-?1?||?j?==?width?-?1)???0?:?*(p?+?dst.step?+?j?+?1);??
- ????????????????uchar?p7?=?(i?==?height?-?1?||?j?==?0)???0?:?*(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;??
- ??
- ????????????????????if?(ap?==?1?&&?p2?*?p4?*?p6?==?0?&&?p4?*?p6?*?p8?==?0)??
- ????????????????????{??
- ????????????????????????//標記??
- ????????????????????????mFlag.push_back(p+j);??
- ????????????????????}??
- ????????????????}??
- ????????????}??
- ????????}??
- ??
- ????????//將標記的點刪除??
- ????????for?(std::vector<uchar?*>::iterator?i?=?mFlag.begin();?i?!=?mFlag.end();?++i)??
- ????????{??
- ????????????**i?=?0;??
- ????????}??
- ??
- ????????//直到沒有點滿足,算法結束??
- ????????if?(mFlag.empty())??
- ????????{??
- ????????????break;??
- ????????}??
- ????????else??
- ????????{??
- ????????????mFlag.clear();//將mFlag清空??
- ????????}??
- ??
- ????????//對點標記??
- ????????for?(int?i?=?0;?i?<?height;?++i)??
- ????????{??
- ????????????uchar?*?p?=?dst.ptr<uchar>(i);??
- ????????????for?(int?j?=?0;?j?<?width;?++j)??
- ????????????{??
- ????????????????//如果滿足四個條件,進行標記??
- ????????????????//??p9?p2?p3??
- ????????????????//??p8?p1?p4??
- ????????????????//??p7?p6?p5??
- ????????????????uchar?p1?=?p[j];??
- ????????????????if?(p1?!=?1)?continue;??
- ????????????????uchar?p4?=?(j?==?width?-?1)???0?:?*(p?+?j?+?1);??
- ????????????????uchar?p8?=?(j?==?0)???0?:?*(p?+?j?-?1);??
- ????????????????uchar?p2?=?(i?==?0)???0?:?*(p?-?dst.step?+?j);??
- ????????????????uchar?p3?=?(i?==?0?||?j?==?width?-?1)???0?:?*(p?-?dst.step?+?j?+?1);??
- ????????????????uchar?p9?=?(i?==?0?||?j?==?0)???0?:?*(p?-?dst.step?+?j?-?1);??
- ????????????????uchar?p6?=?(i?==?height?-?1)???0?:?*(p?+?dst.step?+?j);??
- ????????????????uchar?p5?=?(i?==?height?-?1?||?j?==?width?-?1)???0?:?*(p?+?dst.step?+?j?+?1);??
- ????????????????uchar?p7?=?(i?==?height?-?1?||?j?==?0)???0?:?*(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;??
- ??
- ????????????????????if?(ap?==?1?&&?p2?*?p4?*?p8?==?0?&&?p2?*?p6?*?p8?==?0)??
- ????????????????????{??
- ????????????????????????//標記??
- ????????????????????????mFlag.push_back(p+j);??
- ????????????????????}??
- ????????????????}??
- ????????????}??
- ????????}??
- ??
- ????????//將標記的點刪除??
- ????????for?(std::vector<uchar?*>::iterator?i?=?mFlag.begin();?i?!=?mFlag.end();?++i)??
- ????????{??
- ????????????**i?=?0;??
- ????????}??
- ??
- ????????//直到沒有點滿足,算法結束??
- ????????if?(mFlag.empty())??
- ????????{??
- ????????????break;??
- ????????}??
- ????????else??
- ????????{??
- ????????????mFlag.clear();//將mFlag清空??
- ????????}??
- ????}??
- ????return?dst;??
- }??
- ??
- ??
- int?main(int?argc,?char*argv[])??
- {??
- ????//獲取圖像??
- ????if?(argc?!=?2)??
- ????{??
- ????????std::cout?<<?"參數個數錯誤!"?<<?std::endl;??
- ????????return?-1;??
- ????}??
- ????cv::Mat?src?=?cv::imread(argv[1],?cv::IMREAD_GRAYSCALE);??
- ????if?(src.empty())??
- ????{??
- ????????std::cout?<<?"讀取文件失敗!"?<<?std::endl;??
- ????????return?-1;??
- ????}??
- ??
- ????//將原圖像轉換為二值圖像??
- ????cv::threshold(src,?src,?128,?1,?cv::THRESH_BINARY);??
- ????//圖像細化??
- ????cv::Mat?dst?=?thinImage(src);??
- ????//顯示圖像??
- ????dst?=?dst?*?255;??
- ????cv::namedWindow("src1",?CV_WINDOW_AUTOSIZE);??
- ????cv::namedWindow("dst1",?CV_WINDOW_AUTOSIZE);??
- ????cv::imshow("src1",?src);??
- ????cv::imshow("dst1",?dst);??
- ????cv::waitKey(0);??
- }??
-
運行效果
1原圖像
2.運行效果
總結
- 上一篇: 力场变换
- 下一篇: SSIM与PSNR的计算方式