生活随笔
收集整理的這篇文章主要介紹了
opencv(十三)-快速连通区域分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
索引目錄
1.連通區域標記算法
連接區域標記算法(connected component labeling algorithm)是圖像分析中最常用的算法之一,輸入要求是一張二值(黑白)圖像,屬于同一連通區域的非零像素都是同一定值,算法的實質是掃描一幅圖像的每個像素,由具有相同像素值的相鄰像素組成像素集合一個連通區域,對于找到的每個連通區域,我們賦予其一個唯一的標識(Label),以區別其他連通區域。常見的連通區域分析的算法分為兩類:
Two-Pass法Seed-Filling種子填充法
掃描是基于每個像素單位,對于二值圖像而言,連通區域集合可以是V={1|白色}或者V={0|黑色}, 取決于前景色與背景色的不同。對于灰度圖像來說,連圖區域像素集合可能是一系列在0 ~ 255之間k的灰度值。
在背景分割算法中,連通區域分析常常被用作后處理濾波器,用于去掉小噪聲塊,也常用于OCR這一類含有已知前景待提取的問題中。通過連通區域的統計信息進行篩選。
連通域分析更慢的手動方式是先調用findContours()(傳入cv::RETR_CCOMP標志),隨后在得到的連通域上循環調用cv::drawContours()。
快速連通區域分析算法如下:
int cv
::connectedComponents(
InputArray image
,
OutputArray labels
,
int connectivity
= 8,
int ltype
= CV_32S
)
int cv
::connectedComponentsWithStats(
InputArray image
,
OutputArray labels
,
OutputArray stats
,
OutputArray centroids
,
int connectivity
,
int ltype
,
int ccltype
)
其中stats包括以下枚舉類型數據信息:
CC_STAT_LEFT
組件的左上角點像素點坐標的X位置.
CC_STAT_TOP
組件的左上角點像素點坐標的Y位置.
CC_STAT_WIDTH
組件外接矩形的寬度
CC_STAT_HEIGHT
組件外接矩形的高度.
CC_STAT_AREA
當前連通組件的面積(像素單位)
#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv
;
using namespace std
;RNG
rng(12345);
void connected_component_demo(Mat
&image
);
void connected_component_stats_demo(Mat
&image
);
int main(int argc
, char** argv
) {Mat src
= imread("img/rice.png");if (src
.empty()) {printf("could not load image...\n");}imshow("input", src
);connected_component_stats_demo(src
);waitKey(0);return 0;
}void connected_component_demo(Mat
&image
) {Mat gray
, binary
;cvtColor(image
, gray
, COLOR_BGR2GRAY
);threshold(gray
, binary
, 0, 255, THRESH_BINARY
| THRESH_OTSU
);Mat k
= getStructuringElement(MORPH_RECT
, Size(3, 3), Point(-1, -1));morphologyEx(binary
, binary
, MORPH_OPEN
, k
);morphologyEx(binary
, binary
, MORPH_CLOSE
, k
);imshow("binary", binary
);imwrite("D:/ccla_binary.png", binary
);Mat labels
= Mat
::zeros(image
.size(), CV_32S
);int num_labels
= connectedComponents(binary
, labels
, 8, CV_32S
);printf("total labels : %d\n", (num_labels
- 1));vector
<Vec3b
> colors(num_labels
);colors
[0] = Vec3b(0, 0, 0);for (int i
= 1; i
< num_labels
; i
++) {colors
[i
] = Vec3b(rng
.uniform(0, 256), rng
.uniform(0, 256), rng
.uniform(0, 256));}Mat dst
= Mat
::zeros(image
.size(), image
.type());int w
= image
.cols
;int h
= image
.rows
;for (int row
= 0; row
< h
; row
++) {for (int col
= 0; col
< w
; col
++) {int label
= labels
.at
<int>(row
, col
);if (label
== 0) continue;dst
.at
<Vec3b
>(row
, col
) = colors
[label
];}}imshow("ccla-demo", dst
);imwrite("D:/ccla_dst.png", dst
);
}void connected_component_stats_demo(Mat
&image
) {Mat gray
, binary
;cvtColor(image
, gray
, COLOR_BGR2GRAY
);threshold(gray
, binary
, 0, 255, THRESH_BINARY
| THRESH_OTSU
);Mat k
= getStructuringElement(MORPH_RECT
, Size(3, 3), Point(-1, -1));morphologyEx(binary
, binary
, MORPH_OPEN
, k
);morphologyEx(binary
, binary
, MORPH_CLOSE
, k
);imshow("binary", binary
);Mat labels
= Mat
::zeros(image
.size(), CV_32S
);Mat stats
, centroids
;int num_labels
= connectedComponentsWithStats(binary
, labels
, stats
, centroids
, 8, 4);printf("total labels : %d\n", (num_labels
- 1));vector
<Vec3b
> colors(num_labels
);colors
[0] = Vec3b(0, 0, 0);int b
= rng
.uniform(0, 256);int g
= rng
.uniform(0, 256);int r
= rng
.uniform(0, 256);for (int i
= 1; i
< num_labels
; i
++) {colors
[i
] = Vec3b(0, 255, 0);if (stats
.at
<int>(i
- 1, cv
::CC_STAT_AREA
) < 1700)colors
[i
] = Vec3b(0, 0, 0);}Mat dst
= Mat
::zeros(image
.size(), image
.type());int w
= image
.cols
;int h
= image
.rows
;for (int row
= 0; row
< h
; row
++) {for (int col
= 0; col
< w
; col
++) {int label
= labels
.at
<int>(row
, col
);if (label
== 0) continue;dst
.at
<Vec3b
>(row
, col
) = colors
[label
];}}for (int i
= 1; i
< num_labels
; i
++) {Vec2d pt
= centroids
.at
<Vec2d
>(i
, 0);int x
= stats
.at
<int>(i
, CC_STAT_LEFT
);int y
= stats
.at
<int>(i
, CC_STAT_TOP
);int width
= stats
.at
<int>(i
, CC_STAT_WIDTH
);int height
= stats
.at
<int>(i
, CC_STAT_HEIGHT
);int area
= stats
.at
<int>(i
, CC_STAT_AREA
);printf("area : %d, center point(%.2f, %.2f)\n", area
, pt
[0], pt
[1]);circle(dst
, Point(pt
[0], pt
[1]), 2, Scalar(0, 0, 255), -1, 8, 0);rectangle(dst
, Rect(x
, y
, width
, height
), Scalar(255, 0, 255), 1, 8, 0);}imshow("ccla-demo", dst
);imwrite("D:/ccla_stats_dst.png", dst
);
}
2.剔除小連通區域
剔除小面積連通區域在二值圖像連通區域分析時很有用,之前做的使用采用了for循環的形式,可以使用vector.erase(std::remove_if())的方法, 結合lambda表達式直接剔除。
統計二值圖像的連通區域通過cv::findcontours()實現,二值圖像輪廓的容器是std::vector。連通區域的面積可以由函數cv::contourArea()得到。
剔除小面積連通區域后,可以使用函數cv::drawContours()函數將輪廓畫出,將其第三個參數設置為-1為畫所有輪廓,將其第5個參數設置為cv::FILLED設置為填充。則可以得到剔除后小面積連通后的二值圖像。
#include <opencv2/opencv.hpp>
#include <vector>
#include <algorithm>
int main()
{cv
::Mat img
= cv
::imread("img/pill_002.png");cv
::Mat
imgG(img
.size(), img
.type());cv
::cvtColor(img
, imgG
, cv
::COLOR_BGR2GRAY
);cv
::threshold(imgG
, imgG
, 50, 255, cv
::THRESH_BINARY
);std
::string win1
= "original mask"; std
::string win2
= "after remove";cv
::namedWindow(win1
); cv
::moveWindow(win1
, 10, 10);cv
::namedWindow(win2
); cv
::moveWindow(win2
, 800, 10);cv
::imshow(win1
, imgG
);cv
::waitKey(0); cv
::destroyWindow(win1
); std
::vector
<std
::vector
<cv
::Point
>> contours
;cv
::findContours(imgG
, contours
, cv
::RETR_LIST
, cv
::CHAIN_APPROX_NONE
);contours
.erase(std
::remove_if(contours
.begin(), contours
.end(),[](const std
::vector
<cv
::Point
>& c
) {return cv
::contourArea(c
) < 3000; }),contours
.end());imgG
.setTo(0);cv
::drawContours(imgG
, contours
, -1, cv
::Scalar(255), cv
::FILLED
);cv
::imshow(win2
, imgG
);cv
::waitKey(0); cv
::destroyWindow(win2
); return 0;
}
參考
1.https://blog.csdn.net/jia20003/article/details/80662396
2.https://www.cnblogs.com/zi-wang/p/9800141.html
總結
以上是生活随笔為你收集整理的opencv(十三)-快速连通区域分析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。