|
↑ |
|
← |
|
→ |
|
↓ |
|
|
|
|
|
|
|
1 |
1 |
|
|
|
2 |
2 |
2 |
|
|
|
|
|
|
|
|
2 |
|
|
|
3 |
|
|
|
|
|
|
|
|
|
3 |
3 |
3 |
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
|
4 |
|
4 |
|
|
|
|
|
|
|
4 |
4 |
4 |
|
|
|
|
|
|
|
4 |
|
|
5 |
6 |
6 |
6 |
|
|
|
|
|
|
|
|
|
|
7 |
|
|
|
|
|
|
↖ | ↑ | ↗ |
← |
| → |
↙ | ↓ | ↘ |
|
|
|
|
|
|
1 |
1 |
|
|
|
2 |
2 |
2 |
|
|
|
|
|
|
|
|
2 |
|
|
|
|
3 |
|
|
|
|
|
|
|
|
3 |
3 |
3 |
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
3 |
|
3 |
|
|
|
|
|
|
|
3 |
3 |
3 |
|
|
|
|
|
|
|
3 |
|
|
3 |
4 |
4 |
4 |
|
|
|
|
|
|
|
|
|
|
4 |
|
|
|
|
|
|
다음은 OpenCV 3.0의 라벨링 함수를 이용하여 객체를 라벨링하고,
라벨링 된 객체의 원 영상 픽셀에 접근하여 평균 색상을 추출하는 예제이다.
먼저 원영상(그레이스케일 이미지)을 이진화 하는 과정을 거치고,
adaptiveThreshold(image, binary, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 21, 20);
객체를 라벨링 한다.
int numOfLables = connectedComponentsWithStats(binary, labels,
stats, centroids, 8, CV_32S);
라벨링 된 객체 영역의 평균 색상(그레이 영상이니까 명암) 값을 구한다.
for (int y = 0; y < labels.rows; ++y) {
int *label = labels.ptr<int>(y);
uchar* pixel = image.ptr<uchar>(y);
for (int x = 0; x < labels.cols; ++x) {
int intensity = pixel[x];
// label[x] == 0 은 배경영역에 대한 Blob 계산
if (label[x] == 0) {
cnt[label[x]] = 0;
sum[label[x]] = 0;
}
else {
cnt[label[x]] = cnt[label[x]] + 1;
sum[label[x]] = sum[label[x]] + intensity;
}
}
}
for (int i = 0; i < numOfLables; i++) {
if (i == 0) {
mean[i] = 0;
}
else {
mean[i] = sum[i] / cnt[i];
}
//cout << i << " cnt : " << cnt[i] << endl;
//cout << i << " sum : " << sum[i] << endl;
//cout << i << " mean : " << mean[i] << endl;
}
그 다음 라벨링 된(카운팅 된) 숫자와 명암 값을 이미지 위에 띄운다.
for (int j = 1; j < numOfLables; j++) {
int area = stats.at<int>(j, CC_STAT_AREA);
int left = stats.at<int>(j, CC_STAT_LEFT);
int top = stats.at<int>(j, CC_STAT_TOP);
int width = stats.at<int>(j, CC_STAT_WIDTH);
int height = stats.at<int>(j, CC_STAT_HEIGHT);
int x = centroids.at<double>(j, 0); //중심좌표
int y = centroids.at<double>(j, 1);
//rectangle(color, Point(left, top), Point(left + width, top + height),
// Scalar(0, 0, 255), 1);
putText(color, to_string(j), Point(left + 20, top + 20), FONT_HERSHEY_SIMPLEX,
0.4, Scalar(255, 0, 0), 1);
putText(color, to_string(mean[j]), Point(left + 10, top + 10), FONT_HERSHEY_SIMPLEX,
0.4, Scalar(0, 255, 0), 1);
}
전체 코드와 결과 영상은 아래와 같다.
#include <stdio.h> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main() { Mat image = imread("C:/Users/seohee/Desktop/image.jpg", IMREAD_GRAYSCALE); resize(image, image, Size(), 0.6, 0.6); imshow("original image", image); Mat binary; adaptiveThreshold(image, binary, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 21, 20); imshow("threshold", binary); Mat color; cvtColor(binary, color, CV_GRAY2BGR); Mat labels, stats, centroids; int numOfLables = connectedComponentsWithStats(binary, labels, stats, centroids, 8, CV_32S); int cnt[1000] = { 0, }; int sum[1000] = { 0, }; int mean[1000] = { 0, }; for (int y = 0; y < labels.rows; ++y) { int *label = labels.ptr<int>(y); uchar* pixel = image.ptr<uchar>(y); for (int x = 0; x < labels.cols; ++x) { int intensity = pixel[x]; // label[x] == 0 은 배경영역에 대한 Blob 계산 if (label[x] == 0) { cnt[label[x]] = 0; sum[label[x]] = 0; } else { cnt[label[x]] = cnt[label[x]] + 1; sum[label[x]] = sum[label[x]] + intensity; } } } for (int i = 0; i < numOfLables; i++) { if (i == 0) { mean[i] = 0; } else { mean[i] = sum[i] / cnt[i]; } //cout << i << " cnt : " << cnt[i] << endl; //cout << i << " sum : " << sum[i] << endl; //cout << i << " mean : " << mean[i] << endl; } //cvtColor(image, image, CV_GRAY2BGR); for (int j = 1; j < numOfLables; j++) { int area = stats.at<int>(j, CC_STAT_AREA); int left = stats.at<int>(j, CC_STAT_LEFT); int top = stats.at<int>(j, CC_STAT_TOP); int width = stats.at<int>(j, CC_STAT_WIDTH); int height = stats.at<int>(j, CC_STAT_HEIGHT); int x = centroids.at<double>(j, 0); //중심좌표 int y = centroids.at<double>(j, 1); //rectangle(color, Point(left, top), Point(left + width, top + height), // Scalar(0, 0, 255), 1); putText(color, to_string(j), Point(left + 20, top + 20), FONT_HERSHEY_SIMPLEX, 0.4, Scalar(255, 0, 255), 1); putText(color, to_string(mean[j]), Point(left, top + 20), FONT_HERSHEY_SIMPLEX, 0.4, Scalar(0, 255, 0), 1); } imshow("result", color); waitKey(0); return 0; }
이진화 된 결과 영상
객체 카운팅 및 색상추출, 라벨링(직사각형 표시는 제외하였음)
녹색은 원영상의 명암(색상) 값이고, 분홍색은 카운팅된 숫자이다.
[라벨링 참고자료]
참고자료 1 : http://devmonster.tistory.com/22
참고자료 2 : http://webnautes.tistory.com/823
참고자료 3 : http://poorman.tistory.com/176
[픽셀 접근 참고자료]
참고자료 1 : http://webnautes.tistory.com/1169
참고자료 2 : http://bskyvision.com/
'Programming > OpenCV' 카테고리의 다른 글
[OpenCV] Image Crop (5) | 2020.04.29 |
---|---|
[OpenCV] 동영상 재생 + 프레임 측정 + 적응적 이진화 + 캐니에지 + 컨투어링 + 모멘트 + putText (0) | 2018.10.22 |
[OpenCV] putText 폰트 c++ (0) | 2018.10.18 |
[OpenCV] 특정 픽셀 값 접근하기 (0) | 2018.09.07 |
[OpenCV] image inpaint 함수 (object removal or region filling) (0) | 2018.09.05 |