본문 바로가기
openCV

[openCV] C++ openCV cv::imread 이미지 읽어오기

by rehtorb_s 2020. 10. 11.

저는 오픈소스 라이브러리를 사용해본게 openCV가 처음이었습니다. 해당 api문서를 찾아볼줄도 몰랐고 예제코드만 검색하는 수준이었는데, 어느새 포스팅을 하고 있습니다.. 짧은 지식이지만 openCV를 처음 시작하는 사람들과 함께 공유하고 싶어서, 또 제 개인공부와 복습을 위해 시작하겠습니다.

 

openCV는 영상처리를 위한 라이브러리이며, 무료입니다. 최적화된 알고리즘으로 개개인이 짜는 알고리즘보다 웬만하면 처리속도가 빨라서 많이 쓰입니다. 오늘은 openCV를 사용하며 알아야할 가장 기본적인 이미지 로드를 알아보겠습니다.

 

제일 정확한 정보를 얻고 싶으신 분은 docs.opencv.org/4.4.0/ 에서 공부하셔도 됩니다. 

 

visual studio에서 openCV 개발환경 구축하기

 

기본적으로 openCV의 클래스나 함수를 가져다 쓰려면 범위지정 연산자로 cv 네임스페이스를 지정해줘야 하고, 해당 선언을 하면 일일이 키워드 앞에 cv::를 붙히지 않아도 됩니다.

 
using namespace cv;

 

영상처리를 위해선 이미지를 획득해야하고 이미지의 너비, 높이, 컬러인지 흑백인지에대한 이미지 정보들이 필요합니다. 이러한 데이터를 담는 그릇은 cv::Mat 이란 클래스이고(matrix 약자) 생성자가 오버로딩되어 여러방식으로 초기화(메모리할당)가 가능합니다. 이미지는 cv::imread()함수를 통해 로컬저장소에서 읽어 올 수도 있으며, 너비와 높이, 타입 파라미터로 메모리만 할당할 수도 있습니다. mat.hpp에서 확인하실 수 있습니다. 

 

cv::mat 클래스에 대해서는 다음 포스팅에서 더 자세히 다루도록 하겠습니다.

 

일단 이미지를 읽어 해당 이미지와 특성을 출력해보겠습니다.

 

 

더보기
#include <iostream>
#include <string>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(void)
{
	cv::namedWindow("dog", WINDOW_AUTOSIZE);

	std::string path = ".\\dog.jpg";
	cv::Mat image = cv::imread(path, cv::IMREAD_ANYCOLOR);
	
	if (image.empty())
	{
		std::cerr << "Image Loaded Fail !! " << std::endl;
		return -1;
	}
	
	unsigned char* pData = image.data;
	int width = image.cols;
	int height = image.rows;
	int channel = image.channels();
	int depth = image.depth();
	int type = image.type();

	std::cout << "width : " << width << std::endl;
	std::cout << "height : " << height << std::endl;
	std::cout << "channel : " << channel << std::endl;
	std::cout << "depth : " << depth << std::endl;
	std::cout << "type : " << type << std::endl;

	while (true)
	{
		cv::imshow("dog", image);

		if (waitKey(100) == 27)
			break;
	}
	return 0;
	
}

 

 

 

 

기본적으로 이미지는 height * width 크기의 픽셀로 이루어져 있습니다. 한 픽셀에는 컬러정보가 담기는데 흑백이미지일 경우 Gray이미지로 통칭하며, 8bit ( 0 ~ 255 ) 데이터를 저장합니다. 컬러이미지는 8bit X 3 Channel 총 24bit 데이터가 한 픽셀에 저장되며, RGB가 아닌 B(blue) G(green) R(red) 순서로 데이터가 저장됩니다. 

B(8bit) G(8bit) R(8bit) B G R B G R BGRBGR

 

 

 

콘솔창의 결과와 비교해봅시다.

 

 

cv::imread 함수를 알아보겠습니다.

 

 

첫 번째 파라미터는 이미지 경로입니다. 모든 경로는 해당 프로그램이 실행된 위치부터 시작하며 만약 visual studio에서 프로그램을 실행시켰다면 솔루션(.sln)파일이나 프로젝트(.vcxproj)파일이 있는 위치가 경로의 시작위치입니다. 

빌드 후 exe로 실행을 한다면 시작위치는 exe가 위치한 곳입니다. 

 

두 번째 파라미터는 이미지 타입을 결정할 수 있습니다. 자주 쓰이는 3가지입니다.

매크로네임 설명
IMREAD_GRAYSCALE 0 이미지를 8bit 흑백(gray scale)으로 로드
IMREAD_COLOR 1 이미지를 24bit의 3채널 BGR 컬러로 로드
IMREAD_ANYCOLOR 4 이미지를 24bit의 3채널로 읽지만 gray scale, color 구분없이 로드

imread는 웬만한 확장자는 다 읽을 수 있다해도 과언이 아닙니다. raw이미지가 아닌이상 확장자를 신경쓰시지 않으셔도 됩니다. imgcodecs.hpp 파일에서 확인할 수 있습니다.

 

확장자 참고 이미지

 

소스코드를 보면 이미지의 depth와 type이 있는데

depth : 한 픽셀의 비트수준과 수의 범위를 의미합니다.

 

 

매크로네임 설명
CV_8U 0 8bit, unsigned (0 ~ 255)
CV_8S 1 8bit, signed (-128 ~ 127)
CV_16U 2 16bit, unsigned (0 ~ 65535)
CV_16S 3 16bit, signed (-32768 ~ 32767)
CV_32S 4 32bit, signed (-2147483648 ~ 2147483647)
CV_32F 5 32bit, float (1.18*10e-38 ~ 3.40*10e38)
CV_64F 6 64bit, double (2.23*10e-308 ~ 1.179*10e308)
CV_16F 7 16bit, float

type : depth정보와 함께 채널이 붙습니다. depth + (채널수 - 1) * 2^3의 식으로 반환됩니다.

 

 

따라서 openCV에서 쓰는 타입은 최종적으로 CV_8UC1, CV_32SC3 같은 형태로 쓰이는데

CV_8UC1 : unsigned 8bit 수준의 1채널(총 8bit per pixel) 모노(gray scale) 타입 -> unsigned char

CV_32SC3 : signed 32bit 수준의 3채널(총 96bit per pixel) 컬러 타입 -> int

를 의미합니다.

float나 double타입은 보통 matrix 연산에 필요해서 존재합니다. 언젠가 업로드할(?) 카메라 캘리브레이션에서 카메라의 내부파라미터나 회전, 이동에 필요한 값이 해당 타입의 matrix로 표현됩니다. 

 

 

 

nameWindow는 이미지를 띄울 창의 식별자를 지정함과 동시에 창의 속성을 플래그로 둡니다. 

WINDOW_NORMAL : 사용자가 창 크기 조절 가능, 이미지 크기도 같이 변화

WINDOW_AUTOSIZE : 불러올 이미지에 맞게 자동으로 창 크기를 조절해주는 옵션

WINDOW_FULLSIZE : 원본과 모니터 전체크기 두가지로 조절가능, 단 이미지 변화는 없음

 

 

 

지정한 창에 이미지를 띄워줍니다. nameWindow를 호출하지 않고 imshow만 호출해도 띄워집니다만 WINDOW_FULLSIZE가 디폴트로 적용됩니다.

 

 

 

사용자의 키입력을 기다리는 함수입니다. 단위는 ms이며 우측의 숫자는 ESC키의 ASCII 값입니다.

 

사실 전 imshow가 용량이 큰 이미지를 로드하는데 꽤나 오래걸리는거 같아 잘 사용하지 않습니다. (근데 imshow를 활용한 openCV기반 GUI 오픈소스 cvui가 있더군요. 라이트한 프로그램을 개발하기에 좋아보입니다. 공식홈페이지에서 튜토리얼을 매우 자세하게 제공하는데 추후에 포스팅 해볼 예정입니다.) 대신 Mat클래스로 정의된 이미지 디버깅을 좀 더 편하게 하기 위한 Image Watch라는 도구를 소개하고자 합니다. 

 

 

이미지 픽셀에 커서를 가져다 대면 픽셀 값과 인덱스 번호를 바로 알 수 있어 매우 편리합니다.

 

확장 -> 확장관리 -> image 검색 -> image watch 다운로드

 

 

보기 -> 다른 창 -> Image Watch

 

 

를 이용해서 디버깅을 하며 실시간 영상처리 이미지를 확인할 수 있습니다.

 

다음 포스팅은 cv::Mat 클래스에 대한 자세한 고찰과 픽셀 데이터 접근 방법을 알아보겠습니다.

 

포스팅 내용에 오류가 있거나 지적사항이 있다면 댓글로 달아주세요. 배움을 멈추지 않는 Good Programmer가 되겠습니다. 감사합니다.

'openCV' 카테고리의 다른 글

[openCV] 비주얼스튜디오(visual studio) openCV 적용하기  (0) 2020.07.19

댓글