OpenCV_Segmentation,Labeling - chloe73/openCV GitHub Wiki

๐Ÿ’กSegmentation

Watershed ์•Œ๊ณ ๋ฆฌ์ฆ˜ (์›Œํ„ฐ์‰๋“œ)

โญ๊ฐœ๋…โญ

  1. ์ด๋ฏธ์ง€๋ฅผ ๊ทธ๋ ˆ์ด์Šค์ผ€์ผ๋กœ ๋ณ€ํ™˜ํ•˜๋ฉด ํ”ฝ์…€์˜ ๊ฐ’(0~255)์€ ๋†’๊ณ  ๋‚ฎ์Œ์„ ๊ตฌ๋ถ„ํ• ์ˆ˜ ์žˆ๋‹ค.
  2. ์ด๊ฒƒ์„ ์ง€ํ˜•์˜ ๋†’๋‚ฎ์ด๋กœ ๊ฐ€์ •ํ•˜๊ณ  ๋†’์€ ๋ถ€๋ถ„์„ ๋ด‰์šฐ๋ฆฌ , ๋‚ฎ์€ ๋ถ€๋ถ„์„ ๊ณ„๊ณก์ด๋ผ๊ณ  ํ‘œํ˜„ํ•œ๋‹ค.
  3. ๊ทธ๊ณณ์— ๋ฌผ์„ ๋ถ“๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฌผ์ด ์„ž์ด๋Š” ๋ถ€๋ถ„์ด ์ƒ๊ธธ๊ฒƒ์ด๋‹ค.
  4. ๊ทธ ๋ถ€๋ถ„์— ๊ฒฝ๊ณ„์„ ์„ ๋งŒ๋“ค์–ด ์„œ๋กœ ์„ž์ด์ง€ ์•Š๊ฒŒ ํ•ด์ค€๋‹ค.
  5. ๊ทธ ๊ฒฝ๊ณ„์„ ์„ ์ด๋ฏธ์ง€์˜ ๊ตฌ๋ถ„์ง€์ ์œผ๋กœ ํŒŒ์•…ํ•˜์—ฌ ์ด๋ฏธ์ง€ ๋ถ„ํ• ์„ ํ•œ๋‹ค.

Untitled

์˜์ƒ ๋ถ„ํ• (Image Segmentation)

  • ๋””์ง€ํ„ธ ์˜์ƒ์„ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์˜์—ญ์œผ๋กœ ๋ถ„ํ• ํ•˜๋Š” ๊ณผ์ •์œผ๋กœ Object classification์— ํ™œ์šฉ๋œ๋‹ค.

Untitled

Thresholding

  • ์˜์ƒ์„ ๋ถ„ํ• ํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” Thresholding์ด ์žˆ๋Š”๋ฐ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‘๊ฐ€์ง€ ๊ฐ€์ •์„ ํ•œ๋‹ค.
  1. ๋ถ„ํ• ํ•˜๊ณ  ์‹ถ์€ ๋ฌผ์ฒด์™€ ๋ฐฐ๊ฒฝ์˜ ๋ฐ๊ธฐ๊ฐ’์€ ๋‹ค๋ฅด๋‹ค.
  2. ๋ฐฐ๊ฒฝ ์˜์—ญ ๋‚ด์—์„œ์™€ ๋ฌผ์ฒด ์˜์—ญ ๋‚ด์—์„œ์˜ ๋ฐ๊ธฐ๊ฐ’์˜ ์ฐจ์ด๊ฐ€ ๋ณ„๋กœ ์—†๋‹ค.

์ฃผ์„ 2021-01-10 181015

๐Ÿ’กLabeling

  • ์ด์ง„ํ™” ํ•œ ์ด๋ฏธ์ง€์—์„œ ํ˜•์ฒด๋ฅผ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด ๊ฐ™์€ ํ”ฝ์…€ ๊ฐ’๋“ค๋ผ๋ฆฌ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ๋ฒˆํ˜ธ๋ฅผ ๋งค๊ธด ๊ฒƒ์„ ๋ ˆ์ด๋ธ”๋ง์ด๋ผ๊ณ  ํ•œ๋‹ค.
  • ๋ ˆ์ด๋ธ”๋ง์€ ํฌ๊ฒŒ 4๋ฐฉํ–ฅ๊ณผ 8๋ฐฉํ–ฅ์œผ๋กœ ๋‚˜๋ˆ„์–ด์ง„๋‹ค.
  • 4๋ฐฉํ–ฅ์€ ํ•œ ํ”ฝ์…€์„ ์ค‘์‹ฌ์œผ๋กœ ์ขŒ์šฐ์ƒํ•˜๋กœ ์ธ์ ‘ํ•œ ํ”ฝ์…€์„ ๊ทธ๋ฃนํ™”ํ•˜๊ณ , 8๋ฐฉํ–ฅ์€ ์ขŒ์šฐ์ƒํ•˜์— ๋Œ€๊ฐ์„ 4๋ฐฉํ–ฅ๊ณผ ์ธ์ ‘ํ•œ ํ”ฝ์…€์„ ๊ทธ๋ฃนํ™”ํ•œ๋‹ค.

Untitled Untitled2

C++

๐Ÿ’กImage Segmentation

โœ…Basic method

  1. ์ž„์˜๋กœ ํ•˜๋‚˜์˜ threshold T๋ฅผ ์ •ํ•œ๋‹ค.

  2. T๋ฅผ ์ด์šฉํ•ด ํ•˜๋‚˜์˜ ์˜์ƒ์„ ๋‘๊ฐœ์˜ ์˜์—ญ์œผ๋กœ ๋ถ„ํ• ํ•œ๋‹ค.

  3. ๊ฐ๊ฐ์˜ ์˜์—ญ์— ํ•ด๋‹นํ•˜๋Š” ํ”ฝ์…€์˜ ํ‰๊ท  m1, m2๋ฅผ ๊ตฌํ•œ๋‹ค.

  4. m1, m2์˜ ํ‰๊ท ์œผ๋กœ ์ƒˆ๋กœ์šด threshold T๋ฅผ ๊ตฌํ•œ๋‹ค. T = 0.5X(m1+m2)

  5. ์ฒซ๋ฒˆ์งธ์™€ ๋‘๋ฒˆ์งธ threshold T์˜ ๊ฐ’์ด ์œ ์‚ฌํ•˜๋‹ค๋ฉด ์ข…๋ฃŒํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด 2~4๋‹จ๊ณ„๋ฅผ ๋ฐ˜๋ณตํ•œ๋‹ค.

#include <opencv2/opencv.hpp> 
#include <opencv2/core.hpp> 
#include <opencv2/videoio.hpp> 
#include <opencv2/highgui.hpp> 
#include <stdio.h> 
#include <iostream> 
using namespace cv; 
using namespace std;

int main() 
{ 
	Mat image, thresh; 
	int thresh_T, low_cnt, high_cnt, low_sum, high_sum, i, j, th; 
	thresh_T = 200; // ์ดˆ๊ธฐ threshold ๊ฐ’ 
	th = 10; // ์ดˆ๊ธฐ threshold์™€ ๋‚˜์ค‘ threshold์˜ ๊ฐ’์˜ ์ฐจ์ด์˜ ๊ธฐ์ค€ 
	low_cnt = high_cnt = low_sum = high_sum = 0; 
	image = imread("111.jpg", 0); 
	cout << "threshold value:" << thresh_T << endl; 
	while(1) { 
		for(j = 0; j < image.rows ; j++) { 
			for(i = 0; i < image.cols; i ++) { 
				if(image.at<uchar>(j, i) < thresh_T) { 
					low_sum += image.at<uchar>(j, i); 
					low_cnt++; 
				} else {
					high_sum += image.at<uchar>(j, i); 
					high_cnt++; 
				} 
			} 
		} if(abs(thresh_T - (low_sum / low_cnt + high_sum / high_cnt) / 2.0f) < th) 
		{ 
			break; 
		} else { 
			thresh_T = (low_sum / low_cnt + high_sum / high_cnt) / 2.0f; 
			cout << "threshold value:" << thresh_T << endl; 
			low_cnt = high_cnt = low_sum = high_sum = 0; 
		} 
	} 

	threshold(image, thresh, thresh_T , 255, THRESH_BINARY); 
	imshow("Input image", image); 
	imshow("thresholding", thresh); 
	waitKey(0); 

}

๐Ÿ“[์ถœ๋ ฅ๊ฒฐ๊ณผ]

Untitled1 Untitled2

โœ…Otsu's method

//Otsu's method
#include <opencv2/opencv.hpp> 
#include <opencv2/core.hpp> 
#include <opencv2/videoio.hpp> 
#include <opencv2/highgui.hpp> 
#include <stdio.h> 
#include <iostream> 

using namespace cv; 
using namespace std; 

int main() { 

	Mat image, result; 
	image = imread ("111.jpg", 0); 

	threshold(image, result, 0, 255, THRESH_BINARY | THRESH_OTSU); // 0๊ณผ 255๋Š” minimum & maximum 

	imshow("Input image", image); 
	imshow("result", result); 

	waitKey(0); 

}

๐Ÿ“[์ถœ๋ ฅ๊ฒฐ๊ณผ]

Untitled

โœ…Local (adaptive) thresholding

//Local (adaptive) thresholding
#include <opencv2/opencv.hpp> 
#include <opencv2/core.hpp> 
#include <opencv2/videoio.hpp> 
#include <opencv2/highgui.hpp> 
#include <stdio.h> 
#include <iostream> 

using namespace cv; 
using namespace std; 

int main() { 

	Mat image, binary, adaptive_binary; 
	image = imread("111.jpg", 0); 

	threshold(image, binary, 150, 255, THRESH_BINARY); 
	adaptiveThreshold(image, adaptive_binary, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 85, 15); // 85 : 85X85, 15 : C 

	imshow("Input image", image); 
	imshow("binary", binary); 
	imshow("adaptive binary", adaptive_binary); 

	waitKey(0); 

}

๐Ÿ“[์ถœ๋ ฅ๊ฒฐ๊ณผ]

Untitled4 ๐Ÿ’กLabeling

#include <iostream>  
#include <opencv2/core/mat.hpp>  
#include <opencv2/imgcodecs.hpp>  
#include <opencv2/imgproc.hpp>  
#include <opencv2/highgui.hpp>  

using namespace cv;
using namespace std;

int main() {
    Mat img_gray, img_color, img_binary;

    img_gray = imread("111.jpg", IMREAD_GRAYSCALE);

    threshold(img_gray, img_binary, 127, 255, THRESH_BINARY);
    cvtColor(img_gray, img_color, COLOR_GRAY2BGR);

    Mat img_labels, stats, centroids;
    int numOfLables = connectedComponentsWithStats(img_binary, img_labels,
        stats, centroids, 8, CV_32S);

    //๋ผ๋ฒจ๋ง๋œ ์ด๋ฏธ์ง€์ค‘ ํŠน์ • ๋ผ๋ฒจ์„ ์ปฌ๋Ÿฌ๋กœ ํ‘œํ˜„ํ•ด์ฃผ๊ธฐ  
    for (int y = 0; y < img_labels.rows; ++y) {

        int* label = img_labels.ptr<int>(y);
        Vec3b* pixel = img_color.ptr<Vec3b>(y);

        for (int x = 0; x < img_labels.cols; ++x) {

            if (label[x] == 3) {
                pixel[x][2] = 0;
                pixel[x][1] = 255;
                pixel[x][0] = 0;
            }
        }
    }

    //๋ผ๋ฒจ๋ง ๋œ ์ด๋ฏธ์ง€์— ๊ฐ๊ฐ ์ง์‚ฌ๊ฐํ˜•์œผ๋กœ ๋‘˜๋Ÿฌ์‹ธ๊ธฐ 
    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);

        rectangle(img_color, Point(left, top), Point(left + width, top + height),
            Scalar(0, 0, 255), 1);

        putText(img_color, to_string(j), Point(left + 20, top + 20),
            FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 0), 2);
    }

    imshow("result", img_color);
    waitKey(0);
}

๐Ÿ“[์ถœ๋ ฅ๊ฒฐ๊ณผ]

Untitled5

๐ŸŒC++ ์ฐธ๊ณ  ๋ ˆํผ๋Ÿฐ์Šค ์ž๋ฃŒ

https://yeoeun-ji.tistory.com/17

https://sss20-02.tistory.com/26

๋ผ๋ฒจ๋ง

https://webnautes.tistory.com/823

https://eehoeskrap.tistory.com/279

https://poorman.tistory.com/176

Python

์„ธ๊ทธ๋จผํ…Œ์ด์…˜

Watershed ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋…ธ์ด์ฆˆ ๋“ฑ์œผ๋กœ ์ธํ•ด์„œ ์˜์ƒ ๋ถ„ํ• ์ด ํ•„์š” ์ด์ƒ์œผ๋กœ ๋ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ž˜์„œ OpenCV์—์„œ๋Š” ๋งˆ์ปค ๊ธฐ๋ฐ˜ watershed ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•œ๋‹ค

๋ณ‘ํ•ฉ์ด ๋  ๊ณ„๊ณก์ ๊ณผ ๋ณ‘ํ•ฉ์ด ๋˜์ง€ ์•Š์„ ๊ณ„๊ณก์ ์„ ์ง€์ •ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

Watershed ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ ์šฉํ•˜๊ธฐ ์ „์— ์˜์—ญ์„ ๋‚˜๋ˆ„์–ด ๋ผ๋ฒจ์„ ๋ถ€์—ฌํ•ด์ค€๋‹ค.

์˜ค๋ธŒ์ ํŠธ๋ผ๊ณ  ์ƒ๊ฐ๋˜๋Š” ์˜์—ญ๊ณผ ๋ฐฐ๊ฒฝ์ด๋ผ๊ณ  ์ƒ๊ฐ๋˜๋Š” ์˜์—ญ์— ๋ผ๋ฒจ์„ ๋ถ€์—ฌํ•œ๋‹ค.

ํ™•์‹คํ•˜์ง€ ์•Š์€ ์˜์—ญ์€ ๋ผ๋ฒจ์„ 0์œผ๋กœ ๋ถ€์—ฌํ•œ๋‹ค.

โ†’ ์ด๋Ÿฐ์‹์œผ๋กœ ์ด๋ฏธ์ง€์— ๋ผ๋ฒจ์„ ๋ถ€์—ฌํ•˜๋Š” ๊ฒƒ์„ ๋งˆ์ปค ๋ผ๊ณ  ํ•œ๋‹ค.

์ด์ œ๋ถ€ํ„ฐ Watershed ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ ์šฉํ•œ๋‹ค.

๋งˆ์ปค ์ง€์ ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ๋ผ๋ฒจ๊ฐ’์ด 0์ธ ์˜์—ญ์— ๋Œ€ํ•œ ๋ผ๋ฒจ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

์˜ค๋ธŒ์ ํŠธ ์‚ฌ์ด์˜ ๊ฒฝ๊ณ„์˜ ๋ผ๋ฒจ์€ -1์ด ๋œ๋‹ค.

Untitled

์ด ์ด๋ฏธ์ง€๋Š” ๋™์ „์ด ์„œ๋กœ ๋ถ™์–ด ์žˆ๋‹ค.

watershed ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ Distance Transform์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋กœ ๋ถ™์–ด์žˆ๋Š” ๋™์ „์„ ๋ถ„๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import numpy as np
import cv2 as cv

img = cv2.imread("C:/Users/ParkSangHoon/Desktop/OpenCV_ img_files/coins2.png")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)
 
cv.imshow("result", thresh)
cv.waitKey(0)

์ถœ๋ ฅํ™”๋ฉด

Untitl2ed

์ด์ œ ์˜คํ”„๋‹์„ ์ ์šฉํ•˜์—ฌ ๋…ธ์ด์ฆˆ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ํŒฝ์ฐฝ(dilate) ์—ฐ์‚ฐ์„ ์ ์šฉํ•˜์—ฌ ๋™์ „ ์˜์—ญ ๋‚ด์— ์žˆ์„ ์ˆ˜ ์žˆ๋Š” ๊ณต๋ฐฑ์„ ๋งค๊พผ๋‹ค.

๋™์ „์ด ๊ฒ€์ถœ๋  ์ˆ˜ ์žˆ๋Š” ๋ฐฐ๊ฒฝ ์˜์—ญ = sure_bg

kernel = np.ones((3,3),np.uint8)
opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel, iterations = 2)

sure_bg = cv.dilate(opening,kernel,iterations=3)

๋™์ „ ์ค‘์•™ ๋ถ€๋ถ„์„ ๊ฒ€์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ distance transform๋ฅผ ์ ์šฉํ•œ ํ›„ ์ด์ง„ํ™”๋ฅผ ํ•ฉ๋‹ˆ๋‹ค

์˜ค๋ฅธ์ชฝ ์ด๋ฏธ์ง€๊ฐ€ ๋™์ „ ์˜์—ญ์ด ํ™•์‹คํ•œ ๋™์ „ ์ค‘์•™ ์˜์—ญ(sure_fg)์ž…๋‹ˆ๋‹ค.

dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
result_dist_transform = cv.normalize(dist_transform, None, 255, 0, cv.NORM_MINMAX, cv.CV_8UC1)
ret, sure_fg = cv.threshold(dist_transform, 0.7*dist_transform.max(),255, cv.THRESH_BINARY)

Untitl3ed

๋ฐฐ๊ฒฝ ์˜์—ญ(sure_bg)์—์„œ ๋™์ „ ์ค‘์•™ ์˜์—ญ(sure_fg)๋ฅผ ๋บ€๋‹ค.

sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg,sure_fg)

์•„๋ž˜ ์ด๋ฏธ์ง€์ฒ˜๋Ÿผ ๋™์ „์ธ์ง€ ๋ฐฐ๊ฒฝ์ธ์ง€ ์•„์ง์€ ์•Œ ์ˆ˜ ์—†๋Š” ์˜์—ญ์ด ์กด์žฌํ•˜๊ฒŒ ๋œ๋‹ค.

Untit4led

๋™์ „ ์ค‘์•™ ์˜์—ญ ์ด๋ฏธ์ง€๋ฅผ ๋ผ๋ฒจ๋งํ•œ ํ›„ ์•„์ง ๋™์ „์ธ์ง€ ๋ฐฐ๊ฒฝ์ธ์ง€ ์•Œ ์ˆ˜ ์—†๋Š” ์˜์—ญ์˜ ๋ผ๋ฒจ๊ฐ’์„ 0์œผ๋กœ ์ง€์ •ํ•œ๋‹ค.

๋ฐฐ๊ฒฝ์ด ํ™•์‹คํ•œ ์˜์—ญ์€ 1์ด ๋œ๋‹ค.

# Marker labelling
ret, markers = cv.connectedComponents(sure_fg)

# Add one to all labels so that sure background is not 0, but 1
markers = markers+1

# Now, mark the region of unknown with zero
markers[unknown==255] = 0

watershed ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ ์šฉํ•˜๋ฉด ๋™์ „ ์™ธ๊ณฝ์€ ๋ผ๋ฒจ๊ฐ’์œผ๋กœ -1์„ ๊ฐ€์ง€๋ฉฐ ๋ฐฐ๊ฒฝ์€ ๋ผ๋ฒจ๊ฐ’์œผ๋กœ 1์„ ๊ฐ–๊ฒŒ๋ฉ๋‹ˆ๋‹ค.

markers = cv.watershed(img, markers)

img[markers == -1] = [255, 0, 0]
img[markers == 1] = [255, 255, 0]

Unt5itled

์ „์ฒด์ฝ”๋“œ

import numpy as np
import cv2 as cv

img = cv.imread("C:/Users/ParkSangHoon/Desktop/OpenCV_ img_files/coins2.png")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)

# noise removal
kernel = np.ones((3,3),np.uint8)
opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel, iterations = 2)

# sure background area
sure_bg = cv.dilate(opening,kernel,iterations=3)

# Finding sure foreground area
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
result_dist_transform = cv.normalize(dist_transform, None, 255, 0, cv.NORM_MINMAX, cv.CV_8UC1)
ret, sure_fg = cv.threshold(dist_transform, 0.7*dist_transform.max(),255, cv.THRESH_BINARY)

# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg,sure_fg)

# Marker labelling
ret, markers = cv.connectedComponents(sure_fg)

# Add one to all labels so that sure background is not 0, but 1
markers = markers+1

# Now, mark the region of unknown with zero
markers[unknown==255] = 0

markers = cv.watershed(img, markers)

img[markers == -1] = [255, 0, 0]
img[markers == 1] = [255, 255, 0]

cv.imshow("dist_transform", result_dist_transform)
cv.imshow("unknown", unknown)
cv.imshow("sure_fg", sure_fg)
cv.imshow("sure_bg", sure_bg)
cv.imshow("result", img)
cv.waitKey(0)

๐ŸŒ์ฐธ๊ณ  ๋ ˆํผ๋Ÿฐ์Šค

https://leechamin.tistory.com/281

https://blog.naver.com/samsjang/220601488606

https://webnautes.tistory.com/1281

https://opencv-python.readthedocs.io/en/latest/doc/27.imageWaterShed/imageWaterShed.html

๋ผ๋ฒจ๋ง

๋ผ๋ฒจ๋ง(labeling)์ด๋ž€?

  • ์ด์ง„ํ™”ํ•œ ์ด๋ฏธ์ง€์—์„œ ๊ฐ์ฒด๋ฅผ ๊ฐ๊ฐ ๋ถ„๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ์ธ์ ‘ํ•œ ํ”ฝ์…€ ๊ฐ’๋“ค๋ผ๋ฆฌ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ๋ฒˆํ˜ธ๋ฅผ ๋งค๊ธด ๊ฒƒ์ด๋‹ค.
  • ๋ผ๋ฒจ๋ง์€ ์ขŒ์ธก ์ƒ๋‹จ๋ถ€ํ„ฐ ์šฐ์ธก ์ƒ๋‹จ ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™ํ•˜๋ฉด์„œ ๋ฒˆํ˜ธ๋ฅผ ๋ถ€์—ฌํ•œ๋‹ค.

2247AC38530DCCF731 4๋ฐฉํ–ฅ ๋ผ๋ฒจ๋ง์€ ํ•œ ํ”ฝ์…€์„ ์ค‘์‹ฌ์œผ๋กœ ์‹ญ์ž๊ฐ€ ๋ชจ์–‘์œผ๋กœ ์ธ์ ‘ํ•œ ํ”ฝ์…€์„ ๊ทธ๋ฃนํ™”ํ•œ๋‹ค.

_2021-01-08__6 19 30 _2021-01-08__6 29 55 8๋ฐฉํ–ฅ ๋ผ๋ฒจ๋ง์€ ์‹ญ์ž๊ฐ€ ๋ชจ์–‘์— ๋Œ€๊ฐ์„  ๋ฐฉํ–ฅ๊นŒ์ง€ ๊ณ ๋ คํ•˜์—ฌ ์ธ์ ‘ํ•œ ํ”ฝ์…€์„ ๊ทธ๋ฃนํ™”ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. _2021-01-08__7 03 35 _2021-01-08__7 08 09

Labeling ๊ตฌํ˜„ํ•˜๊ธฐ

  • ๋ ˆ์ด๋ธ”๋ง(๋ผ๋ฒจ๋ง) ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ 0์€ ๋ฐฐ๊ฒฝ 1์ด์ƒ์€ ๊ฐ์ฒด(Object)๋กœ ํŒ๋‹จํ•œ๋‹ค.

๋ ˆ์ด๋ธ”๋ง ํ•จ์ˆ˜ cv2.connectedComponents()

  • ๋ ˆ์ด๋ธ”๋ง ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ ˆ์ด๋ธ”๋งต์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ ˆ์ด๋ธ”๋ง ํ•จ์ˆ˜

retval, labels = cv2.connectedComponent(image, lable=None, connectivity=None, ltype=None) 
  • return
    • retval: ๊ฐ์ฒด ๊ฐœ์ˆ˜ +1(๋ฐฐ๊ฒฝ) ์„ ๋ฐ˜ํ™˜
    • labels: ๋ ˆ์ด๋ธ”๋งต ํ–‰๋ ฌ ๋ฐ˜ํ™˜
  • parameter
    • image: 8๋น„ํŠธ 1์ฑ„๋„ ์˜์ƒ
    • labels: ๋ ˆ์ด๋ธ” ๋งต ํ–‰๋ ฌ(์ž…๋ ฅ ์˜์ƒ๊ณผ ๊ฐ™์€ ํฌ๊ธฐ, numpy.ndarray)
    • connectivity: 4 ๋˜๋Š” 8(default)
    • type: label ํƒ€์ž…. cv2.CV_32S(default) ๋˜๋Š” cv2.CV_16S
import cv2 as cv

#์ด๋ฏธ์ง€๋ฅผ ํ‘๋ฐฑ์œผ๋กœ ๋ถˆ๋Ÿฌ์˜จ ํ›„ ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ ๋ณ€ํ™˜(์ด์ง„ํ™”)
img = cv.imread("test.jpg", cv.IMREAD_GRAYSCALE)
ret, binar = cv.threshold(img, 0, 255, cv.THRESH_OTSU)

#๋ ˆ์ด๋ธ”๋ง
retval, labels = cv2.connectedComponent(binar)

๊ฐ์ฒด ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ ˆ์ด๋ธ”๋ง ํ•จ์ˆ˜

๊ฐ์ฒด ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ ˆ์ด๋ธ”๋ง ํ•จ์ˆ˜ cv2.connectedComponentsWithStats()

  • object์˜ ์œ„์น˜์™€ ํฌ๊ธฐ, ์ค‘์‹ฌ์œ„์น˜, ํ”ฝ์…€๋ฉด์ ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค
retval, labels, stats, centroids = cv2.connectedComponentsWithStats(image, labels=None, stats=None, centroids=None, connectivity=None, ltype=None)
  • return
    • retval: ๊ฐ์ฒด ๊ฐœ์ˆ˜ +1(๋ฐฐ๊ฒฝ) ์„ ๋ฐ˜ํ™˜
    • labels: ๋ ˆ์ด๋ธ”๋งต ํ–‰๋ ฌ ๋ฐ˜ํ™˜
    • stats: Nํ–‰ 5์—ด, N์€ retval ๊ฐ’์ด๋ฉฐ, 5์—ด์—๋Š” x, y, width, height, area ์ˆœ์œผ๋กœ ์ €์žฅ๋จ
    • centroids: Nํ–‰ 2์—ด, 2์—ด์—๋Š” ๋ฌด๊ฒŒ์ค‘์‹ฌ ์ขŒํ‘œ์ธ x, y๊ฐ€ ์ €์žฅ๋จ
  • parameter
    • image: 8๋น„ํŠธ 1์ฑ„๋„ ์˜์ƒ
    • labels: ๋ ˆ์ด๋ธ” ๋งต ํ–‰๋ ฌ(์ž…๋ ฅ ์˜์ƒ๊ณผ ๊ฐ™์€ ํฌ๊ธฐ, numpy.ndarray)
    • stats: ๊ฐ Object์˜ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค, ํ”ฝ์…€ ๋ฉด์ ์„ ๋‹ด์€ ํ–‰๋ ฌ(numpy.ndaeeay.shape(N, 5), dtype=numpy.int32)
    • centroids: ๊ฐ ๊ฐ์ฒด์˜ ๋ฌด๊ฒŒ ์ค‘์‹ฌ ์œ„์น˜ ์ •๋ณด๋ฅผ ๋‹ด์€ ํ–‰๋ ฌ numpy.ndarray. shape=(N, 2), dtype=numpy.float64.
    • connectivity: 4 ๋˜๋Š” 8(default)
    • ltype: label ํƒ€์ž…. cv2.CV_32S(default) ๋˜๋Š” cv2.CV_16S
import cv2 as cv

#์ด๋ฏธ์ง€๋ฅผ ํ‘๋ฐฑ์œผ๋กœ ๋ถˆ๋Ÿฌ์˜จ ํ›„ ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ ๋ณ€ํ™˜(์ด์ง„ํ™”)
img = cv.imread("test.jpg", cv.IMREAD_GRAYSCALE)
ret, binar = cv.threshold(img, 0, 255, cv.THRESH_OTSU)

#๋ ˆ์ด๋ธ”๋ง
retval, labels, stats, centroids = cv2.connectedComponentWithStats(binar)

์˜ˆ์ œ

import cv2 as cv
import random

def setRandColor(min=0, max=255): #๋žœ๋ค์ƒ‰์ƒ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
    while True:
        r = random.randrange(0, max)
        g = random.randrange(0, max)
        b = random.randrange(0, max)
        if not(r < min and g < min and b < min):
            return r, g, b

source = "source/test.jpeg"
origin = cv.imread(source, cv.IMREAD_COLOR)
origin = cv.resize(origin, (720, 720))
img = cv.cvtColor(origin, cv.COLOR_BGR2GRAY)
img = cv.GaussianBlur(img, (9, 9), 0)

ret, binar = cv.threshold(img, 0, 255, cv.THRESH_OTSU)
cv.imshow("binar", binar)
cnt, labels, stats, centroid = cv.connectedComponentsWithStats(binar)
count = 0
for i in range(0, cnt):
    (x, y, w, h, area) = stats[i]
    if area < 100:
        continue
    if area > 1500:
        continue
    if w > 700:
        continue
    if h > 700:
        continue

    cv.rectangle(origin, (x, y, w, h), (0, 255, 255))
    count += 1
    string = str(count)
    cv.putText(origin, string, (x, y), cv.FONT_HERSHEY_PLAIN, 1.2, setRandColor(128, 255))

cv.imshow("Labeling", origin)
cv.waitKey(0)
cv.destroyAllWindows()
_2021-01-08__9 52 47 _2021-01-08__9 51 50

์ฐธ์กฐ

https://eehoeskrap.tistory.com/279

https://webnautes.tistory.com/823

https://poorman.tistory.com/176

https://jvvp.tistory.com/1085

https://deep-learning-study.tistory.com/228

https://devmonster.tistory.com/22

โš ๏ธ **GitHub.com Fallback** โš ๏ธ