[OpenCV] 라벨링 개념, 객체 카운팅 + 색상 추출 + 라벨링 예제
|
↑ |
|
← |
|
→ |
|
↓ |
|
|
|
|
|
|
|
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/
'Development & Tools > Tools & Environments' 카테고리의 다른 글
| [Linux] 리눅스 wget 명령어 (0) | 2018.11.26 |
|---|---|
| [OpenCV] 동영상 재생 + 프레임 측정 + 적응적 이진화 + 캐니에지 + 컨투어링 + 모멘트 + putText (0) | 2018.10.22 |
| [OpenCV] putText 폰트 c++ (0) | 2018.10.18 |
| [Embedded linux] 'make menuconfig' requires the ncurses libraries. 오류 해결법 (0) | 2018.10.08 |
| [Embedded linux] 보드에 연결된 Serial Port 부팅 확인 (0) | 2018.10.06 |