[Intel AI SW 아카데미] 영상처리 - 이진 영상의 침식과 팽창

Jimeaning·2023년 11월 16일
0

Intel AIoT

목록 보기
18/38

23.11.16 (목) 41일차

이진 영상의 침식과 팽창

침식

첫 번째 도형 날개 부분이 줄어든 걸 확인할 수 있다.
침식할 때는 데이터가 사라질 수 있음을 유의하고 사용해야 한다.
마스크 크기를 늘려주면 더 많이 침식된다

#pragma once

#include "ISP.h"

int main()
{
	std::string fileName = "../KCCImageNet/images/circle_plate.png";
	cv::Mat src_gray = cv::imread(fileName, cv::ImreadModes::IMREAD_GRAYSCALE);

	Mat src_bin;
	threshold(src_gray, src_bin, 150, 255, ThresholdTypes::THRESH_BINARY);

	uchar* pData = src_bin.data;
	size_t width = src_gray.cols;
	size_t height = src_gray.rows;

	Mat src_erosion = Mat::zeros(height, width, CV_8UC1);

	// 침식 (erosion)
	const int SE_sz = 3;
	int SE_half_sz = SE_sz / 2;
	int SE_Cross[SE_sz * SE_sz] =
	{
		0, 255, 0,
		255, 255, 255,
		0, 255, 0,
	};
	int SE_Rect[SE_sz * SE_sz] =
	{
		255, 255, 255,
		255, 255, 255,
		255, 255, 255,
	};
    
    // full image searching
    uchar* pDst = src_erosion.data;

    for (size_t row = SE_half_sz; row < height - SE_half_sz; row++) {
        for (size_t col = SE_half_sz; col < width - SE_half_sz; col++) {
            //struct element
            bool allone = true;
            for (int h = -SE_half_sz; h <= SE_half_sz; h++) {
                for (int w = -SE_half_sz; w <= SE_half_sz; w++) {
                    int index = (row + h) * width + (col + w);
                    int index_SE = (h + SE_half_sz) * SE_sz + (w + SE_half_sz);
                    uchar input = pData[index];
                    //input == 0 : background
                    bool condition = (input == 0 && SE_Cross[index_SE] == 255);
                    if (condition == true)
                    {
                        allone = false;
                        break;
                    }
                }
                if (!allone) break;
            }
            if (allone)
                pDst[row * width + col] = 255;
            else
                pDst[row * width + col] = 0;
        }
    }
    
    uchar* pErosion = pDst;
    for (size_t row = SE_half_sz; row < height - SE_half_sz; row++) {
        for (size_t col = SE_half_sz; col < width - SE_half_sz; col++) {
            bool condition = false;
            for (int h = -SE_half_sz; h <= SE_half_sz; h++) {
                for (int w = -SE_half_sz; w <= SE_half_sz; w++) {
                    int index = (row + h) * width + (col + w);
                    int index_SE = (h + SE_half_sz) * SE_sz + (w + SE_half_sz);
                    uchar input = pErosion[index];
                    //input == 0 : background
                    condition = (input == 255 && SE_Cross[index_SE] == 255);
                    if (condition == true)
                    {
                        break;
                    }
                }
                if (condition == true)
                {
                    break;
                }
            }
        }
    }
  
  
	return 1;
}

팽창

#pragma once

#include "ISP.h"

int main()
{
	std::string fileName = "../KCCImageNet/images/circle_plate.png";
	cv::Mat src_gray = cv::imread(fileName, cv::ImreadModes::IMREAD_GRAYSCALE);

	Mat src_bin;
	threshold(src_gray, src_bin, 150, 255, ThresholdTypes::THRESH_BINARY);

	uchar* pData = src_bin.data;
	size_t width = src_gray.cols;
	size_t height = src_gray.rows;

	Mat src_dilation = Mat::zeros(height, width, CV_8UC1);

	const int SE_sz = 3;
	int SE_half_sz = SE_sz / 2;
	int SE_Cross[SE_sz * SE_sz] =
	{
		0, 255, 0,
		255, 255, 255,
		0, 255, 0,
	};
	int SE_Rect[SE_sz * SE_sz] =
	{
		255, 255, 255,
		255, 255, 255,
		255, 255, 255,
	};
    
    // full image searching
	uchar* pDst = src_dilation.data;

	for (size_t row = SE_half_sz; row < height - SE_half_sz; row++) {
		for (size_t col = SE_half_sz; col < width - SE_half_sz; col++) {
			//struct element
			bool allone = true;
			for (int h = -SE_half_sz; h <= SE_half_sz; h++) {
				for (int w = -SE_half_sz; w <= SE_half_sz; w++) {
					int index = (row + h) * width + (col + w);
					int index_SE = (h + SE_half_sz) * SE_sz + (w + SE_half_sz);
					uchar input = pData[index];
					//input == 0 : background
					bool condition = (input == 0 && SE_Cross[index_SE] == 255);
					if (condition == true)
					{
						allone = false;
						break;
					}
				}
				if (!allone) break;
			}
			if (allone)
				pDst[row * width + col] = 255;
			else
				pDst[row * width + col] = 0;
		}
	}
    
	// dilation
	uchar* pDilation = src_dilation.data;
	for (size_t row = SE_half_sz; row < height - SE_half_sz; row++) {
		for (size_t col = SE_half_sz; col < width - SE_half_sz; col++) {
			bool condition = false;
			if (condition == true)
			{
				for (int h = -SE_half_sz; h <= SE_half_sz; h++) {
					for (int w = -SE_half_sz; w <= SE_half_sz; w++) {
						int index = (row + h) * width + (col + w);
						int index_SE = (h + SE_half_sz) * SE_sz + (w + SE_half_sz);
						if (SE_Cross[index_SE] == 255)
							pDilation[index] = 255;
					}
				}
			}
		}
	}

	return 1;
}

OpenCV 라이브러리 활용

shape 모양원본 이미지축소 이미지팽창 이미지

int kernelSz = 1;
int shape = MorphShapes::MORPH_CROSS;
Size sz = Size(2 * kernelSz + 1, 2 * kernelSz + 1);
Mat SE = getStructuringElement(shape, sz);

// 침식 erode
// src :: src_bin
Mat src_erode;
erode(src_bin, src_erode, SE);
Mat diff_erode = src_bin - src_erode;

Mat src_dilate;
dilate(src_bin, src_dilate, SE);

Mat diff_dilate = src_dilate - src_bin;

이진 영상의 열림과 닫힘

Opening

첫 번째 도형의 날개가 사라진 걸 볼 수 있다

Closing


세 번째 도형이 붙었다

코드

int kernelSz = 3;
int shape = MorphShapes::MORPH_CROSS;
Size sz = Size(2 * kernelSz + 1, 2 * kernelSz + 1);
Mat SE = getStructuringElement(shape, sz);

// 침식 erode
// src :: src_bin
Mat src_erode;
erode(src_bin, src_erode, SE);
Mat diff_erode = src_bin - src_erode;

Mat src_dilate;
dilate(src_bin, src_dilate, SE);
Mat diff_dilate = src_dilate - src_bin;

// extension
Mat src_open, src_closing;
int type = MorphTypes::MORPH_OPEN;
morphologyEx(src_bin, src_open, type, SE);

type = MorphTypes::MORPH_CLOSE;
morphologyEx(src_bin, src_closing, type, SE);

Brake 영상 처리

원본 영상

이진화 처리

Opening으로 노이즈 제거하고 다시 사이즈 유지시키기하는 이유: contour가 15개가 출력되는데, 우리 눈에 보이는 건 6개 뿐이다. 자잘한 것들이 잡힌다는 뜻이기 때문에 침식하고 팽창시킨다
(침식만 시키면 원 사이즈가 줄어든다)

drawing

Result Image

#pragma once

#include "ISP.h"

int main()
{
	std::string fileName = "../KCCImageNet/images/brake_disk/brake_disk_part_01.png";
	cv::Mat src_gray = cv::imread(fileName, cv::ImreadModes::IMREAD_GRAYSCALE);
	Mat src_result;
	cvtColor(src_gray, src_result, cv::COLOR_GRAY2BGR);

	uchar* pData = src_gray.data;
	size_t width = src_gray.cols;
	size_t height = src_gray.rows;

	Mat src_bin = Mat::zeros(Size(width, height), CV_8UC1);
	uchar* pDataBin = src_bin.data;

	int threshold = 245;
	// 이진화, Binary
	for (size_t i = 0; i < width * height; i++)
	{
		int value = pData[i];

		(value > threshold) ? pDataBin[i] = 255 : pDataBin[i] = 0;
	}

	int kernelSz = 2;
	int shape = MorphShapes::MORPH_CROSS;
	cv::Size sz = Size(2 * kernelSz + 1, 2 * kernelSz + 1);
	Mat SE = getStructuringElement(shape, sz);

	Mat src_open;
	int type = MorphTypes::MORPH_OPEN;
	morphologyEx(src_bin, src_open, type, SE);

	RNG rng(12345);
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	findContours(src_open, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
	Mat drawing = Mat::zeros(src_open.size(), CV_8UC3);
	for (size_t i = 0; i < contours.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawing, contours, (int)i, color, -2, LINE_8, hierarchy, 0);

		int CoGx, CoGy;
		CoGx, CoGy = 0, 0;
		int rad;
		int accX = 0, accY = 0;
		int length = contours[i].size();
		int x_min = width, x_max = 0, y_min = height, y_max = 0;
		for (size_t n = 0; n < length; n++)
		{
			accX += contours[i].at(n).x;
			accY += contours[i].at(n).y;

			if (x_min > contours[i].at(n).x)
				x_min = contours[i].at(n).x;
			if (x_max < contours[i].at(n).x)
				x_max = contours[i].at(n).x;
			if (y_min > contours[i].at(n).y)
				y_min = contours[i].at(n).y;
			if (y_max < contours[i].at(n).y)
				y_max = contours[i].at(n).y;
		}
		CoGx = accX / length;
		CoGy = accY / length;

		rad = (x_max - x_min) / 2;

		drawContours(src_result, contours, (int)i, CV_RGB(255, 255, 0), -2, LINE_8, hierarchy, 0);
		line(src_result, Point(CoGx, CoGy - rad), Point(CoGx, CoGy + rad), CV_RGB(255, 0, 0), 5);

		double area = contourArea(contours[i]);
		double arcLen = arcLength(contours[i], true);

		string msg;
		msg = format("area = %.1f", area);
		putText(src_result, msg, Point(CoGx, CoGy + 30 * 0), FONT_HERSHEY_SIMPLEX, 1, CV_RGB(0, 0, 255), 2, 8);
		msg = format("x,y = %d, %d", CoGx, CoGy);							  	 
		putText(src_result, msg, Point(CoGx, CoGy + 30 * 1), FONT_HERSHEY_SIMPLEX, 1, CV_RGB(0, 0, 255), 2, 8);
		msg = format("length = %.1f", arcLen);									   	 
		putText(src_result, msg, Point(CoGx, CoGy + 30 * 2), FONT_HERSHEY_SIMPLEX, 1, CV_RGB(0, 0, 255), 2, 8);
	}

	return 1;
}
profile
I mean

0개의 댓글