지금까지 배운 내용을 토대로 10가지 정도의 이미지 프로세싱 알고리즘을 opencv로 구현하여 매트랩에서 제공하는 함수와의 차이를 확인해보자
-
Quantization
- 매트랩 코드
1
2
3
4
5
6
7
8 |
clear; clc;
x=imread('boat.png');
f=floor(double(x)/32);
q1=uint8(f*32);
subplot(1,2,1), imshow(x), subplot(1,2,2), imshow(q1);
[psnr, snr] = psnr(x,q1);
psnr |
cs |
- opencv 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 |
#include <stdio.h>
#include <Windows.h>
#include "opencv2/opencv.hpp"
#include <cmath>
using namespace cv;
void ft_color_depth_reduction(Mat &image, int labels){
int h = image.rows; // height (영상의 높이)
int w = image.cols; // width (영상의 너비)
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
// 0-255 level (gray image) 인 경우 :
if (image.channels() == 1)
{
uchar data = image.at<uchar>(y, x);
data = data / labels * labels + labels / 2;
image.at<uchar>(y, x) = data;
}
// RGB level (color image) 인 경우 :
else if (image.channels() == 3)
{
Vec3b colVal = image.at<Vec3b>(y, x);
colVal[2] = colVal[2] / labels * labels + labels / 2;
colVal[1] = colVal[1] / labels * labels + labels / 2;
colVal[0] = colVal[0] / labels * labels + labels / 2;
image.at<Vec3b>(y, x) = colVal;
}
}
}
}
void main()
{
Mat srcimage = imread("boat.png", -1); // 변환할 영상
if (!srcimage.data)
{
printf("No Image Found\n");
return;
}
namedWindow("Original Image", WINDOW_AUTOSIZE);
imshow("Original Image", srcimage);
Mat outimage = srcimage.clone();
int num = 32;
ft_color_depth_reduction(outimage, num);
imshow("Output Image", outimage);
waitKey(0);
destroyAllWindows();
} |
cs |
-
결과 사진 비교
-
매트랩
2. opencv
-
이미지 회전
-
매트랩 코드
-
opencv 코드
-
결과비교
-
매트랩
2. opencv
Opencv 와 matlab을 이용하여 이미지의 회전을 하였습니다. 회전은 반시계방향으로 45도를 회전하였습니다. 회전 후의 이미지는 두 opencv 와 matlab은 차이가 있었습니다. 눈으로 봐도 명확히 알 수 있던 것이 opencv를 이용하여 이미지는 사진의 가장자리는 깨끗이 나온 것을 알 수 있습니다. 허나 matlab의 경우에는 aliasing 이 발생한다는 것을 알 수 있었습니다. 이는 설정에 따른 차이때문입니다. opencv에서는 cv2DRotationMatrix()를 이용하였습니다.
매트랩의 경우에는 imrotate()를 사용하였습니다.
Imrotate( A, angle ) <- A : image,
-
fft -> ifft
-
매트랩 코드
1
2
3
4
5 |
ca=imread('Matlab_Image/lenna.jpg');
%ca = rgb2gray(ca);
ca_F=fft2(double(ca));
ca_FI=ifft2(ca_F);
subplot(1,2,1),imshow(ca),subplot(1,2,2),imshow(ca_FI,[]); |
cs |
-
opencv 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 |
#include <stdio.h>
#include <opencv2/core/core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat I = imread("lenna.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if (I.empty())
return -1;
Mat padded; //expand input image to optimal size
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols); // on the border add zero values
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI); // Add to the expanded another plane with zeros
dft(complexI, complexI); // this way the result may fit in the source matrix
// compute the magnitude and switch to logarithmic scale
// => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
Mat magI = planes[0];
magI += Scalar::all(1); // switch to logarithmic scale
log(magI, magI);
// crop the spectrum, if it has an odd number of rows or columns
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
// rearrange the quadrants of Fourier image so that the origin is at the image center
int cx = magI.cols / 2;
int cy = magI.rows / 2;
Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
normalize(magI, magI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a
//normalize(phaseVals, phaseVals, 0, 1, CV_MINMAX);
// viewable image form (float between values 0 and 1).
imshow("Input Image", I); // Show the result
imshow("Spectrum Magnitude", magI);
//waitKey();
//calculating the idft
cv::Mat inverseTransform;
cv::dft(complexI, inverseTransform, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT);
normalize(inverseTransform, inverseTransform, 0, 1, CV_MINMAX);
imshow("Reconstructed", inverseTransform);
waitKey();
return 0;
} |
cs |
-
결과 비교
-
매트랩
2. opencv
-
Gaussian
-
매트랩 코드
1
2
3
4
5
6
7
8
9
10
11 |
tic
origin = imread('engineer.tif');
noise_img = imnoise(origin,'gaussian',0,0.02);
filt = fspecial('average',[5,5]);
result = filter2(filt,noise_img);
imshow(noise_img);
figure(),imshow(result/255);
toc |
cs |
-
opencv 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 |
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <time.h>
IplImage* GaussianNoiseCreate(IplImage *img, int std);
>> 가우시안 노이즈를 생성하는 함수의 프로토타입 선언
void main() {
clock_t start, end;
start = clock();
double result;
IplImage *srcImage = cvLoadImage("engineer.tif", -1);
>> 가우시안 노이즈를 입히고 제거하기 위해서 이미지를 불러옵니다.
>> cvLoadImage(“원하는 이미지파일명”,-1);로 Load합니다.
//가우시안 잡음 이미지 생성
//가우시안 잡음 : 가우시안 밀도 함수를 갖는 잡음 (표준편차가 클수록 잡음이 많이 포함됨)
IplImage *noiseImage = GaussianNoiseCreate(srcImage, 20);
>> 작성하는 GaussinNoiseCreate 함수를 통해 원본이미지를 Gaussian 노이즈를 입힌다. 이때 두번째 파라미터 값인 표준편차가 클수록 많은 양의 노이즈를 씌워줄수 있다.
>> srcImage에 가우시안 노이즈를 발생시켜서 noiseImage에 넣어준다.
IplImage* resultImage = cvCreateImage(cvGetSize(noiseImage), IPL_DEPTH_8U, 1);
cvSmooth(noiseImage, resultImage, CV_BLUR, 5, 5);
>> 가우시안 노이즈를 평균 필터링을 통해 제거한다 , 필터의 크기는 5x5로 설정되었으며, 노이즈의 양이 많으면 더 큰 크기의 필터의 사용이 필요하며, 수행속도가 느려진다.반대로 노이즈의 크기가 작으면 작은 크기의 필터의 사용이 필요하며, 수행속도가 빨라진다. 따라서 노이즈의 크기를 보고서 알맞은 필터크기를 선정해주는 것이 중요하다.
end = clock();
result = (double)(end - start);
printf("수행시간은 %f초입니다.", result/1000);
//create window
cvNamedWindow("source", CV_WINDOW_AUTOSIZE);
cvNamedWindow("remove", CV_WINDOW_AUTOSIZE);
//show image
cvShowImage("source", noiseImage);
cvShowImage("remove", resultImage);
cvWaitKey(0);
//release image
cvReleaseImage(&noiseImage);
cvReleaseImage(&resultImage);
}
//가우시안 잡음 생성 함수
IplImage* GaussianNoiseCreate(IplImage *img, int std) {
int height = img->height;
int width = img->width;
int step = img->widthStep;
uchar* data = (uchar*)img->imageData;
int imgSize = width * height *img->nChannels;
time_t nowTime;
srand(time(&nowTime));
int r1, r2;
double random1, random2, normal, stdNormal, tmp;
do {
r1 = rand() % width;
r2 = rand() % height;
>> 가우시안 잡음 생성 함수에서 r1과 r2는 이미지에서 노이즈를 발생시킬 위치를 랜덤으로 정하는 것이다.
random1 = (double)rand() / RAND_MAX;
random2 = (double)rand() / RAND_MAX;
stdNormal = sqrt(-2.0 * log(random1)) * cos(2 * 3.14159 * random2);
normal = std * stdNormal;
>> std는 표준편차로 아래 if문을 통해 데이터 값의 범위를 0~255범위의 임의의 값으로 만들 때 사용한다.
int index = r1 * step + r2;
if (index >= imgSize) {
index = imgSize - 1;
}
tmp = data[index] + normal;
if (tmp < 0) { data[index] = 0; }
else if (tmp > 255) { data[index] = 255; }
else { data[index] = (unsigned char)tmp; }
imgSize--;
} while (imgSize > 0);
return img;
} |
cs |
-
결과비교
-
매트랩
2. opencv
검정색 출력창은 visual Open-CV로 가우시안 노이즈 생성 및 제거를 수행했을때의 시간 이고 하얀색 출력창은 Matlab에서 가우시안 노이즈 생성 및 제거를 수행했을때의 시간이다. Open-CV와 Matlab의 성능은 사람의 눈으로 구분하기에는 큰 차이를 구별할 수가 없는 수준이다.
하지만 수행시간에는 차이를 보였다. 약 0.4초정도가 Open-CV로 처리하였을 때 더빠른 속도처리를 볼수있었다.
또한 평균필터링을 통해서 노이즈 제거한 이미지에서 노이즈가 제거되었지만 노이즈 뿐만 아니라 원이미지의 성분도 잃어버려서 원본이미지와는 조금의 차이가 보인다.
이것은 Imgae Enhancement를 적용하여서 원이미지와 비슷하게 만들어주는 기법이 필요해보인다.
-
histogram equalization
-
매트랩 코드
-
opencv 코드
-
결과비교
-
opencv
2. 매트랩
-
Canny edge
-
매트랩 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 |
Origin_image=imread('eye.tif');
BW1 = edge(Origin_image,'Canny');
imshow(BW1); title("Canny");
%% color
이 프로그램은 원본 이미지를 YCbCr 색 공간으로 변환하여 컬러 이미지의 가장자리를 찾습니다.
%eye.tif
%susan.tif
img=imread('susan.tif');
[x y z]=size(img);
if z==1
rslt=edge(img,'canny');
elseif z==3
img1=rgb2ycbcr(img);
dx1=edge(img1(:,:,1),'canny');
dx1=(dx1*256);
img2(:,:,1)=dx1;
img2(:,:,2)=img1(:,:,2);
img2(:,:,3)=img1(:,:,3);
rslt=ycbcr2rgb(uint8(img2));
end
R=rslt;
imshow(R); title("Canny"); |
cs |
-
opencv 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 |
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv/cv.h"
#include <stdlib.h>
#include <stdio.h>
#include<time.h>
using namespace std;
void main()
{
clock_t start, end;
double result;
IplImage* srcImage = cvLoadImage("susan.tif", CV_LOAD_IMAGE_GRAYSCALE);
IplImage* cannyImage1 = cvCreateImage(cvGetSize(srcImage), IPL_DEPTH_8U, 1);
if (srcImage == NULL)
return;
cvNamedWindow("cannyImage1", CV_WINDOW_AUTOSIZE); //window 화면 뛰우기
start = clock();
cvCanny(srcImage, cannyImage1, 50, 100, 3);
end = clock();
cvShowImage("CannyImage1", cannyImage1);
cvWaitKey(0);
cvDestroyAllWindows();
cvReleaseImage(&cannyImage1);
result=(double)(end - start);
printf("%f", result);
} |
cs |
-
결과비교
-
매트랩
2. opencv
-
Salt & pepper noise
-
매트랩 코드
1
2
3
4
5
6
7
8
9 |
tic
img = imread('cameraman.tif');
subplot(1,2,1);
imshow(img);
title('Original image')
subplot(1,2,2);
imshow(imnoise(img,'salt & pepper'));
title('salt & pepper');
toc |
cs |
-
opencv 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 |
#include<opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
void salt(cv::Mat &image, int n);
int main()
{
cv::Mat image = cv::imread("house.jpg");
salt(image, 1000);
cv::namedWindow("my image");
cv::imshow("my image", image);
cv::waitKey(5000);
return 1;
}
void salt(cv::Mat &image, int n) {
for (int k = 0; k < n; k++) {
int i = rand() % image.cols;
int j = rand() % image.rows;
if (image.channels() == 1) {
image.at<uchar>(j, i) = 255;
}
else if (image.channels() == 3) {
image.at<cv::Vec3b>(j, i)[0] = 255;
image.at<cv::Vec3b>(j, i)[1] = 255;
image.at<cv::Vec3b>(j, i)[2] = 255;
}
}
} |
cs |
-
결과비교
-
매트랩
2. opencv
같은 알고리즘을 수행한 결과 opencv가 매트랩보다 노이즈가 덜 한 것을 관찰할 수 있었습니다.
매트랩의 salt & pepper noise구현은 검은색과 흰색의 노이즈가 보이지만
opencv로 만들어본 nosie는 흰색의 노이즈만 관찰되었습니다.
-
sobel edge detect
-
매트랩 코드
1
2
3
4
5
6
7
8
9 |
tic
og = imread('cameraman.tif');
subplot(1,2,1);
imshow(og);
title('Original image')
subplot(1,2,2);
imshow(edge(og,'sobel'));
title('sobel edge');
toc |
cs |
-
opencv 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 |
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "iostream"
#include <time.h>
#include <stdio.h>
using namespace cv;
using namespace std;
void main()
{
clock_t start, end;
start = clock();
double result;
Mat src1;
src1 = imread("engineer.tif", CV_LOAD_IMAGE_COLOR);
namedWindow("Original image", CV_WINDOW_AUTOSIZE);
imshow("Original image", src1);
Mat grey;
cvtColor(src1, grey, CV_BGR2GRAY); // 그레이 영상으로 변환
Mat sobelx, sobely;
Sobel(grey, sobelx, CV_32F, 1, 0); // Sobel 엣지 검출
Sobel(grey, sobely, CV_32F, 0, 1);
namedWindow("vertical edge", CV_WINDOW_AUTOSIZE);
imshow("vertical edge", sobelx);
namedWindow("horizontal edge", CV_WINDOW_AUTOSIZE);
imshow("horizontal edge", sobely);
end = clock();
result = (double)(end - start);
printf("time %f", result / 1000);
waitKey(0);
} |
cs |
-
결과 비교
-
매트랩
경과시간 : 0.350917 sec
2. opencv
경과시간 : 0.108000 sec
matlab과 같이 opencv를 이용해 sobel edge detect를 수행한 결과
opencv를 이용한 것이 수행시간이 더 줄었습니다.
-
LOG(Laplacian of gaussian) 으로 엣지 검출
-
매트랩 코드
1
2
3
4
5
6
7
8 |
I=imread('bacteria.tif');
figure(1);imshow(I);
BW=edge(I,'log');
LoG(가우스-라플라시안) 필터를 사용하여 I를 필터링한 후 영점교차를 찾아서 경계를 찾습니다.
figure(2);imshow(BW); |
cs |
-
opencv 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 |
#include <opencv2\opencv.hpp>
#include <time.h>
#include <cstdio>
using namespace cv;
using namespace std;
int main() {
clock_t begin, end;
Mat image = imread("bacteria.tif",0);
CV_Assert(image.data);
double sigma = 1.4;
Mat dst1, gaus_img;
// 시간측정 시작.
begin = clock();
GaussianBlur(image, gaus_img, Size(9, 9), sigma, sigma);
//가우시안 필터 씌우기
Laplacian(gaus_img, dst1, -1, 5);
//Laplacian을 통해 이차 미분을 할 수 있고, 따라서 edge를 검출 할 수 있다.
end = clock();
imshow("image", image);
imshow("dst2- LOG_OpenCV", dst1);
cout << "수행시간(초) : " << (double)(end - begin) / CLOCKS_PER_SEC << endl;
waitKey();
return 0;
} |
cs |
-
결과비교
-
매트랩
2. opencv
이번에는 특이하게 opencv의 수행시간이 더 걸렸는데 매트랩결과와 비교해보았을 때, opencv의 윤곽선이 더 진합니다.
Opencv는 비교적 디테일이 남아있는 모습을 보여줍니다.
이것을 없애고 싶다면 가우시안 필터를 더 키우면 될 것입니다.
-
DCT -> IDCT
-
매트랩 코드
1
2
3
4
5
6
7
8
9 |
ca=imread('house.jpg');
ca = rgb2gray(ca);
ca_F=dct2(double(ca));
ca_F1=idct2(ca_F);
ca_F = uint8(ca_F);
ca_F1 = uint8(ca_F1);
subplot(1,3,1),imshow(ca),title('original image');
subplot(1,3,2),imshow(ca_F),title('DCT image');
subplot(1,3,3),imshow(ca_F1),title('IDCT image'); |
cs |
-
opencv 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 |
#include <stdlib.h>
#include <stdio.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image = imread("house.jpg", 0); // grayscale
Mat fimage;
image.convertTo(fimage, CV_32F, 1.0 / 255);
imshow("Original Image", image);
Mat dimage;
dct(fimage, dimage);
imshow("DCT Image", dimage);
Mat dimage2;
dct(dimage, dimage2, DCT_INVERSE);
imshow("IDCT", dimage2);
waitKey();
return 0;
} |
cs |
먼저 컬러 이미지 ‘house.jpg’를 gray이미지로 변환하고 dct2 함수를 이용해서 gray이미지를 이산코사인 변환 하고, idct2 함수를 이용해서 원본 이미지로 복원합니다.
-
결과비교
-
매트랩
2. opencv
OpenCV로 했을 때와 Matlab으로 했을 때 IDCT를 비교해보면 두 이미지의 차이가 심하지 않은 걸 볼 수 있습니다.
원본 이미지와 복원한 이미지를 비교해 보아도 달라진 점을 찾을 수 없는 것으로 보아 DCT의 손실율이 매우 작은 것을 확인 할 수 있었습니다.
'영상처리 실습' 카테고리의 다른 글
matlab wavelets toolbox (0) | 2018.12.06 |
---|---|
노이즈 복원&엣지 검출 실습 (0) | 2018.11.20 |