printf("ho_tari\n");

Chapter3 : Point, Size, Rect, Range, Mat 클래스 본문

OpenCV

Chapter3 : Point, Size, Rect, Range, Mat 클래스

호타리 2023. 9. 12. 17:15

<OpenCV_Projects.cpp>

#include <opencv2/opencv.hpp>

extern void show_images();                            // show_images()가 외부에 있다는 의미
extern void show_code_3();                            // show_code_3()가 외부에 있다는 의미
extern void show_code_3_8();                          // show_code_3_8()가 외부에 있다는 의미
extern void show_code_3_9();                          // show_code_3_9()가 외부에 있다는 의미
extern void show_code_3_10();                         // show_code_3_10()가 외부에 있다는 의미
extern void show_code_3_11();                         // show_code_3_11()가 외부에 있다는 의미
extern void show_code_3_12();                         // show_code_3_12()가 외부에 있다는 의미
extern void show_code_3_13();
extern void show_code_3_16();

int main()
{
    std::cout << CV_VERSION << std::endl;
    //show_images();                                    // show_images() 실행
    //show_code_3();                                    // show_code_3() 실행
    //show_code_3_8();                                  // show_code_3_8() 실행
    //show_code_3_9();                                  // show_code_3_9() 실행
    //show_code_3_10();                                 // show_code_3_10() 실행
    //show_code_3_11();                                 // show_code_3_11() 실행
    //show_code_3_12();                                   // show_code_3_12() 실행
    //show_code_3_13();
    show_code_3_16();
}

 

<show_code_3.cpp>

#pragma once
#include <opencv2/opencv.hpp>

void show_code_3()
{
	cv::Point pt1;	//default 생성자
	pt1.x = 5;
	pt1.y = 10;
	cv::Point pt2(pt1);	// 복사 생성자
	cv::Point p3 = pt1 + pt2;	// 연산자 overloading
	int dot1 = pt1.dot(pt2);    // 두점의 내적을 구함 (inner product pt1 vector pt2 vector)
	
	std::cout << pt2 << std::endl;

	cv::Size sz1(10, 20);	// 너비 10 높이 20 size 클래스
	cv::Size sz2;		// default 생성자
	cv::Size sz3 = sz1 + sz2;
	int sz4 = sz1.area();	// 넓이 : 10 * 20

	std::cout << sz1 << std::endl;

	cv::Rect rc1(0, 10, 0 + 60, 10 + 30);	// (0, 10) 부터 너비 60 높이 40 직사각형
	cv::Rect rc2 = rc1 + cv::Size(50, 40);	// rc1이 시작점 그로부터 50 x 40 직사각형
	cv::Rect rc3 = rc2 + cv::Point(60, 60);	// rc2 사각형 위치 (60, 60)만큼 이동

	cv::Range r1(0, 10);	// int i = 0; i < 10; ++i => 0 ~ 9
	//std::string == cv::String, typedef std::string String

	cv::String str1 = "Hello";
	cv::String str2 = "World";
	cv::String str3 = str1 + str2;	// 연산자 overloading

	for (int i = 0; i < 10; ++i)
	{
		cv::String str = cv::format("TEST %d", i);	// sprintf(), 특정 형식 문자열 생성 위해 format() 함수 이용
		std::cout << str << std::endl;
	}

	cv::Mat mat1(800, 800, CV_8UC3, cv::Scalar(255, 0, 0));	// 800 x 800 행렬, type : uchar(8비트 unsigned char, 3-channels), 모든 픽셀값이 (255, 0, 0)으로 초기화(B, G, R)
	cv::Mat mat2(800, 800, CV_8UC1, cv::Scalar(127));		// 800 x 800 행렬, type : uchar(8비트 unsigned char, 1-channel), 모든 픽셀값이 127로 초기화
	std::cout << "[ 10, 20 ] : " << static_cast<int>(mat2.at<uchar>(10, 20)) << std::endl;		// mat2 행렬의 [ 10, 20 ]의 원소값을 참조
	
	cv::Mat mat3(255 + cv::Mat::zeros(900, 900, CV_8UC1));	// 900 x 900 행렬의 모든 원소값을 0으로 초기화, 255 + 0 이므로 흰색 출력
	cv::Mat mat4(255 * cv::Mat::ones(900, 900, CV_8UC1));	// 900 x 900 행렬의 모든 원소값을 1로 초기화, 255 * 1 이므로 흰색 출력
	cv::Mat mat5(255 * cv::Mat::eye(900, 900, CV_8UC1));	// 900 x 900 Identity 행렬, 255 * 1이므로 흰색 대각선 출력

	cv::imshow("Mat1", mat1);
	cv::imshow("Mat2", mat2);
	cv::imshow("Mat3", mat3);
	cv::imshow("Mat4", mat4);
	cv::imshow("Mat5", mat5);
	cv::waitKey();
	cv::destroyAllWindows();

}

<compile 결과>

 

<show_code_3_8.cpp>

#pragma once
#include <opencv2/opencv.hpp>

void show_code_3_8()
{
	cv::Mat img1{ cv::imread("dog.bmp") };	// C++11 uniform initializer, 초기화 한번만 가능
	if (img1.empty())
	{
		std::cout << "파일이 없습니다." << std::endl;
		return;
	}
	std::cout << img1.size << std::endl;

	cv::Mat img2 = img1;	// 복사 생성자 shallow copy

	cv::Mat img3 = img1.clone();	// deep copy

	cv::imshow("IMG1", img1);
	cv::imshow("IMG2", img2);
	cv::imshow("IMG3", img3);

	cv::waitKey();

	// 아무키를 누르면 원본 이미지가 변경
	img1.setTo(cv::Scalar(0, 255, 255));	// img1을 노란색으로 바꿈

	cv::imshow("IMG1", img1);
	cv::imshow("IMG2", img2);	// img2는 img1의 shallow copy여서 노란색으로 바뀐다
	cv::imshow("IMG3", img3);	// img3는 deep copy여서 노란색으로 바뀌지 않는다

	cv::waitKey();

	cv::destroyAllWindows();
	
}

 

<compile 결과>

 

<show_code_3_9,cpp>

#pragma once
#include <opencv2/opencv.hpp>

void show_code_3_9()
{
	cv::Mat img1 = cv::imread("cat.bmp");

    if (img1.empty())
    {
        std::cout << "파일이 없습니다." << std::endl;
        return;
    }

    cv::Mat img2 = img1(cv::Rect(270, 120, 340, 240));	// 연산자 overloading, 직사각형 모양으로 선정한 위치 부분의 사진 자르기
    cv::Mat img3 = img1(cv::Rect(270, 120, 340, 240)).clone();	// deep copy

    cv::imshow("IMG1", img1);
    cv::imshow("IMG2", img2);
    cv::imshow("IMG3", img3);
    cv::waitKey();

    img2 = ~img2;	// not, 비트 반전

    cv::imshow("IMG2", img2);
    cv::imshow("IMG3", img3);

    cv::waitKey();

    cv::destroyAllWindows();
}

<compile 결과>

 

<show_code_3_10.cpp>

#pragma once
#include <opencv2/opencv.hpp>

void show_code_3_10()
{
	std::cout << "===========================================================================" << std::endl;

	cv::Mat mat1(cv::Mat::zeros(10, 10, CV_8UC1));									// 모든 원소값이 0인 10 x 10 행렬

	for (int i = 0; i < mat1.rows; ++i)
	{
		for (int j = 0; j < mat1.cols; ++j)
		{
			std::cout <<static_cast<int>(mat1.at<uchar>(i, j)) << "\t";				// mat1의 행을 i, 열을 j로 하여 행렬 원소값 출력
		}
		std::cout << std::endl;														// row 하나가 완성되면 줄바꿈하여 다음 row 시작
	}

	std::cout << "===========================================================================" << std::endl;

	cv::Mat mat2(cv::Mat::ones(10, 10, CV_8UC1));									// 모든 원소값이 1인 10 x 10 행렬

	for (int i = 0; i < mat2.rows; ++i)
	{
		for (int j = 0; j < mat2.cols; ++j)
		{
			std::cout << static_cast<int>(mat2.at<uchar>(i, j)) << "\t";			// mat2의 행을 i, 열을 j로 하여 행렬 원소값 출력, get
		}
		std::cout << std::endl;														// row 하나가 완성되면 줄바꿈하여 다음 row 시작
	}

	std::cout << "===========================================================================" << std::endl;

	uchar value{ 0u };		// uniform initializer

	for (int i = 0; i < mat1.rows; ++i)
	{
		for (int j = 0; j < mat1.cols; ++j)
		{
			mat1.at<uchar>(i, j) = ++value;			// mat1 행렬의 원소에 1씩 증가한 값들을 대입, set
		}
		std::cout << std::endl;
	}

	std::cout << "===========================================================================" << std::endl;

	for (int i = 0; i < mat1.rows; ++i)
	{
		for (int j = 0; j < mat1.cols; ++j)
		{
			std::cout << static_cast<int>(mat1.at<uchar>(i, j)) << "\t";				// mat1의 행을 i, 열을 j로 하여 행렬 원소값 출력
		}
		std::cout << std::endl;														// row 하나가 완성되면 줄바꿈하여 다음 row 시작
	}

	std::cout << "===========================================================================" << std::endl;

}

 

<compile 결과>

 

<show_code_3_11,cpp>

#pragma once
#include <opencv2/opencv.hpp>

void show_code_3_11()
{
	cv::Mat img1 = cv::imread("coins.png", cv::IMREAD_UNCHANGED);	// 바꾸지 말라는 의미

	if (img1.empty())
	{
		return;
	}

	std::cout << "PNG channel : " << img1.channels() << std::endl;	// channel이 몇개인지 반환
	std::cout << "PNG column : " << img1.cols << std::endl;	// column 수 반환
	std::cout << "PNG row : " << img1.rows << std::endl;	// row 수 반환
	std::cout << "PNG size : " << img1.size << std::endl;	// size 타입 반환

	if (img1.channels() == CV_8UC1)	// channel이 1개라면 gray scale
	{
		std::cout << "Grayscale" << std::endl;
	}
	else if (img1.channels() == CV_8UC3)	// channeldl 3개라면 color
	{
		std::cout << "Color" << std::endl;
	}
	else           // 아무것도 아니면 png
	{
		std::cout << "PNG image" << std::endl;	
	}
}

 

<compile 결과>

 

<show_code_3_12.cpp>

#pragma once
#include <opencv2/opencv.hpp>

void show_code_3_12()
{
	float data[] = {1.0f, 2.0f, 3.0f, 4.0f};

	std::cout << "=====================" << std::endl;

	cv::Mat mat1(2, 2, CV_32FC1, data);	// 1차원 배열을 행렬 형태로 바꿔줌
	std::cout << mat1 << std::endl;

	std::cout << "=====================" << std::endl;

	cv::Mat mat2 = mat1.inv();		// 역행렬로 만들어줌
	std::cout << mat2 << std::endl;

	std::cout << "=====================" << std::endl;

	cv::Mat mat3 = mat1 * mat2;		// 행렬과 행렬의 역행렬을 곱하면 I 행렬(identity matrix)가 만들어짐
	std::cout << mat3 << std::endl;

	std::cout << "=====================" << std::endl;

	cv::Mat mat4 = mat1.t();	// 행과 열을 서로 바꿔줌(transpose, 전치)
	std::cout << mat4 << std::endl;

	std::cout << "=====================" << std::endl;

	cv::Mat mat5 = mat1 + mat4;	// 두 행렬의 합
	std::cout << mat5 << std::endl;

	std::cout << "=====================" << std::endl;

	cv::Mat img1 = cv::imread("lenna.bmp");
	cv::imshow("IMG1", img1);
	
    cv::Mat img2 = img1.t();	// 불러온 이미지 transpose
	cv::imshow("IMG2", img2);

	cv::Mat img3 = img1 + 100;	// 이미지의 픽셀값들을 전부 100씩 증가
	cv::imshow("IMG3", img3);

	cv::Mat img4 = cv::imread("lenna.bmp", cv::IMREAD_GRAYSCALE);	// 이미지를 회색으로 불러옴
	cv::imshow("IMG4", img4);
	
    cv::Mat img5 = img4 + 100;	// 회색 이미지의 픽셀값을 전부 100씩 증가시키면 밝기가 밝아진다
	cv::imshow("IMG5", img5);

	cv::Mat img6 = img4 - 50;	// 회색 이미지의 픽셀값을 전부 50씩 감소시키면 밝기가 어두워진다
	cv::imshow("IMG6", img6);

	cv::waitKey();
	cv::destroyAllWindows();
}

<compile 결과>

 

<show_code_3_13.cpp>

#pragma once
#include <opencv2/opencv.hpp>

void show_code_3_13()
{
	cv::Mat img1 = cv::imread("lenna.bmp", cv::IMREAD_GRAYSCALE);	// lenna.bmp 이미지를 회색 이미지로 불러옴
	cv::Mat img2;
	img1.convertTo(img2, CV_32FC1);	// img1의 타입을 변경해줌
	uchar data1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };	// 배열을 만들어줌
	cv::Mat mat1(3, 4, CV_8UC1, data1);	// 배열을 mat1 행렬에 넣어줌

	std::cout << "mat1 : \n" << mat1 << std::endl;

	cv::Mat mat2 = mat1.reshape(0, 1);	// 3 x 4 크기의 mat1 행렬을 1 x 12 크기의 행렬로 변환, reshape(channel, row) ((0, 1)은 channel은 0으로 바꾸지 않는다는 의미, 1은 row를 1로 바꾼다는 의미)

	std::cout << "mat2 : \n" << mat2 << std::endl;

	cv::Mat mat3 = cv::Mat::ones(1, 4, CV_8UC1) * 255;	//모든 원소가 255로 구성된 1 x 4 크기의 행렬 mat3 생성
	mat1.push_back(mat3);	// 3 x 4 크기의 mat1 행렬에 1 x 4 크기의 mat3 행렬을 맨 마지막 행으로 추가

	std::cout << "mat1 : \n" << mat1 << std::endl;

	/*
	cv::imshow("IMG2", img2);
	cv::waitKey();
	cv::destroyAllWindows();
	*/
}

<compile 결과>

 

<show_code_3_16.cpp>

#pragma once
#include <opencv2/opencv.hpp>

void show_code_3_16()
{
	cv::Scalar blue = 128;	// Scalar 클래스 타입의 변수 blue에 128 정수 하나를 이용하여 초기화
	std::cout << "blue : " << blue << std::endl;

	cv::Scalar yellow(0, 255, 255);	// Scalar 클래스 타입의 변수 yellow의 4개의 double형 원소 중 처음 세 원소가 0, 255, 255로 설정, 마지막 네번째 원소는 0으로 초기화
	std::cout << "yellow : " << yellow << std::endl;

	cv::Mat img1(800, 800, CV_8UC3, yellow);

	cv::imshow("IMG1", img1);
	cv::waitKey();
	cv::destroyAllWindows();
}

<compile 결과>