Lab.2 Point Processing and Histogram

짱J·2022년 3월 19일
0
post-thumbnail

I/O and Mat

  • Mat 클래스 : OpenCV에서 이미지와 이미지의 정보 (사이즈 등)를 담게 되는 클래스
  • 입출력 함수 : 기본적으로 Mat 객체로 반환하거나 Mat 객체를 입력으로 받아 수행

    imread() : 이미지 읽기
    imshow() : 이미지 출력
    imwrite() : 이미지 쓰기

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

using namespace cv;
using namespace std;

int main() {
	// 경로와 확장자에 주의!
	Mat src_img = imread("images/landing.jpg", 1);
    // flag = 1: 컬러 영상으로 읽음
    // flag = 0 : 흑백 영상으로 읽음
    // flage = -1 : 원본 영상의 형식대로 읽음

	imshow("Test window", src_img);
	waitKey(0);
	destroyWindow("Test window");
}

#include "opencv2/opencv.hpp" 를 이용하여 모든 헤더파일을 불러올 수 있지만, 그렇게 하면 프로그램 실행 속도가 느려지므로 필요한 헤더파일만 불러오도록 하자.


Pixel Value

  • 이미지의 각 픽셀을 개별적으로 접근
  • OpenCV의 함수들을 사용하게 되면 사용할 경우가 없으나, 픽셀 값을 각각 읽어 원하는 기능을 구현하거나 분석할 때 반드시 피룡함
  • OpenCV의 컬러 mat는 BGR 채널 순서를 가지고 있음에 유의
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;
using namespace std;

Mat SpreadSalts(Mat img, int num) {
	// num : 점을 찍을 개수
	for (int n = 0; n < num; n++) {
		int x = rand() % img.cols; // img.cols는 이미지의 폭 정보를 저장
		int y = rand() % img.rows; // img.rows는 이미지의 높이 정보를 저장
		/*
		* 나머지는 나누는 수를 넘을 수 없으므로
		* 이미지의 크기를 벗어나지 않도록 제한하는 역할을 해줌
		*/

		if (img.channels() == 1) {
			// img.channels() : 이미지의 채널 수르 반환
			img.at<char>(y, x) = 255; // 단일 채널 접근
		}
		else {
			img.at<Vec3b>(y, x)[0] = 255; // Blue 채널 접근
			img.at<Vec3b>(y, x)[1] = 255; // Green 채널 접근
			img.at<Vec3b>(y, x)[2] = 255; // Rud 채널 접근
		}
	}

	return img;
}

int main() {
	Mat src_img = imread("images/landing.jpg", 0);

	Mat salted_img = SpreadSalts(src_img, 1000);

	imshow("Test window", salted_img);
	waitKey(0);
	destroyWindow("Test window");
}
  • 강의 노트에는 함수의 반환형이 void이나, 이를 salted_img라는 변수로 저장하기 위해 Mat 타입으로 반환하도록 변경
  • 단일 채널은 그레이 스케일 이미지이다.
  • img.at(int x, int y) : 각 원소에 접근하기 위해 사용
    • uchar : 그레이(흑백) 이미지에 사용
    • vec3b : 컬러 이미지에 사용, 3개의 unsigned char를 가지는 벡터


Histogram

: 픽셀 값의 분포를 나타낸 그래프

  • 가능한 모든 픽셀 레벨에 대한 카운트로 구할 수 있음
  • 이미지의 픽셀 값에 대한 경향성을 알 수 있으므로, 시각적인 분석/판단에 용이
// 히스토그램 계산 함수
  void cv::calcHist( const Mat* images, // 입력 영상의 주소(& 붙여야 함)
  					 int nimages, // 입력 영상의 개수
  					 const int* channels, // 히스토그램을 구할 채널을 나타내는 배열
  					 InputArray mask, // 계산을 수행할 범위 마스크, Mat()으로 전체 선택
  					 OutputArray hist, // 히스토그램이 저장될 Mat
  					 int dims,
  					 const int* histSize, // 가능한 모든 픽셀 레벨 (일반 8bit 영상은 255)
  					 const float ** ranges, // 히스토그램 범위
  					 bool uniform = true, // 히스토그램이 등간격인지 아닌지
  					 bool accumulate = false // 일반 히스토그램인지 누적 히스토그램인지
  				   )

이를 사용해서 히스토그램을 출력하는 코드를 작성해보자.

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

using namespace cv;
using namespace std;

Mat getHistogram(Mat& src) {
	Mat histogram;
	const int* channel_numbers = { 0 };
	float channel_range[] = { 0.0, 255.0 };
	const float* channel_ranges = channel_range;
	int number_bins = 255;

	// 히스토그램 계산
	calcHist(&src, 1, channel_numbers, Mat(), histogram, 1, &number_bins, &channel_ranges);

	// 히스토그램 plot
	int hist_w = 512;
	int hist_h = 400;
	int bin_w = cvRound((double)hist_w / number_bins);

	Mat histImage(hist_h, hist_w, CV_8UC1, Scalar(0, 0, 0));
	// 정규화
	normalize(histogram, histogram, 0, histImage.rows, NORM_MINMAX, -1, Mat());

	for (int i = 1; i < number_bins; i++) {
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(histogram.at<float>(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(histogram.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
	}

	return histImage;
}

int main() {
	Mat src_img = imread("images/landing.jpg", 0);
	Mat hist_img = getHistogram(src_img);

	imshow("Test window", hist_img);
	waitKey(0);
	destroyWindow("Test window");
}


Operations

  • 산술 연산으로 두 영상을 합성하거나 영상의 값을 전체적으로 조절할 수 있음
  • 산술 연산을 위한 함수가 따로 존재하지만, 산술 연산자도 사용 가능
  virtual void cv::resize ( InputArray src,
  							OutputArray dst,
  							Size dsize,
  							double fx = 0,
  							double fy = 0,
  							int interpolation = INTER_LINEAR
  						  ) 
  
  virtual void cv::MatOp::add ( const MatExpr& expr1,
  							   const MatExpr& expr2,
  							   MatExpr& res
  							 ) const
  
  virtual void cv::MatOp::add ( const MatExpr& expr1,
  							   const Scalar& s,
  							   MatExpr& res
  							 ) const
  
  virtual void cv::MatOp::subtract ( const MatExpr& expr1,
  							  		const MatExpr& expr2,
  							   		MatExpr& res
  							 	  ) const
  
  virtual void cv::MatOp::subtract ( const Scalar& s,
  							   		const MatExpr& expr,
  							   		MatExpr& res
  							      ) const


Logical Operations

  • 영상에 대한 논리적 연산으로 두 영상을 합성하거나 Masking할 수 있음

    void cv::bitwise_and( inputArray src1,
    						 inputArray src2,
    						 OutputArray dst,
    						 inputArray mask = noArray()
    					   )
    
    void cv::bitwise_or( inputArray src1,
    						 inputArray src2,
    						 OutputArray dst,
    						 inputArray mask = noArray()
    					   )
    
    void cv::bitwise_not( inputArray src1,
    						 inputArray src2,
    						 OutputArray dst,
    						 inputArray mask = noArray()
    					   )
    <p align="center" style="color:gray">


Binarization

  • 영상을 두 개의 값으로 표현하는 것 (0 or 1, 0 or 255)
  • Grayscale 영상에서 임계점보다 크고 작음을 기준으로 영상을 두 개의 값으로 나눌 수 있음
  • 적절한 임계 값을 설정하면 영상 속에서 유용한 마스크를 획득할 수 있음
  • 적절한 임계 값은 히스토그램을 참조해 선택하거나 자동으로 찾아주는 알고리즘을 이용해 탐색 (OTSU)
      Mat color_img = imread("mark.jpg", 1);
      
      Mat gray_img;
      // 이진화를 위해 color에서 grayscale 영상으로 변환
      cvtColor(color_img, gray_img, CV_BGR2GRAY);
      
      Mat binary_img1, binary_img2;
      // 임계값 지정 이진화
      threshold(gray_img, binary_img1, 127, 255, THRESH_BINARY);
      // 임계값 자동 이진화
      threshold(gray_img, binary_img1, 0, 255, THRESH_OTSU);

profile
[~2023.04] 블로그 이전했습니다 ㅎㅎ https://leeeeeyeon-dev.tistory.com/

0개의 댓글