영상 정합(image patch similarity)

컴퓨터비전/영상처리 2015. 4. 4. 00:40

영상의 패치 정합

1. SSD(Sum of Squared Difference)

같은 위치에 있는 픽셀의 차를 구해서 제곱한 값을 다 더해 영역의 유사성 측정을 한다.

유사할 경우 0에 가깝다.


2. SAD(Sum Of Absolute Difference)

같은 위치에 있는 픽셀의 차를 절대값 하고 다 더해 영역의 유사성 측정을 한다.

SSD와 마찬가지로 유사할 경우 0에 가깝다.



3. NCC(Normalized Cross Correlation)

NCC는 SSD와 SAD가 갖는 밝기 차의 문제를 결하기 위해 사용하는 중 하나이다. 

두 영역의 픽셀 평균값과 표준편차를 계산하여 평균 값기가 0, 표준편차는 1이 되도록 정규화한다.


m은 평균 밝기를 나타내며 σ는 표준편차이다.



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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <cv.h>
#include <highgui.h>
#include <iostream>
 
using namespace cv;
using namespace std;
 
int SSD(Mat &src1, Mat &src2, Point pt1, Point pt2, int patch_size)
{
    // Range Check
    if ((pt1.x - patch_size) < || (pt2.x - patch_size) < || (pt1.x + patch_size) >= src1.rows ||
        (pt2.x + patch_size) >= src2.rows || (pt1.y - patch_size) < || (pt2.y - patch_size) < ||
        (pt1.y + patch_size) >= src1.cols || (pt2.y + patch_size) >= src2.cols)
        throw exception("SSD::Inavlid range");
 
    // Image Channel Check
    if (src1.channels() != src2.channels())
        throw exception("SSD::Image channel not same");
 
    int nSum = 0;
    
    unsigned char *src1_ptr = (unsigned char*)src1.data;
    unsigned char *src2_ptr = (unsigned char*)src2.data;
    int src1_cn = src1.channels();
    int src2_cn = src2.channels();
 
    for (int r = -patch_size; r <= patch_size; r++)
    {
        for (int c = -patch_size; c <= patch_size; c++)
        {
            for (int l = 0; l <= src1_cn; l++)
            {
                nSum += ((src1_ptr[(pt1.x + r) * src1.cols * src1_cn + (pt1.y + c) * src1_cn + l]) - (src2_ptr[(pt2.x + r) * src2.cols * src2_cn + (pt2.y + c) * src2_cn + l]))
                    * ((src1_ptr[(pt1.x + r) * src1.cols * src1_cn + (pt1.y + c) * src1_cn + l]) - (src2_ptr[(pt2.x + r) * src2.cols * src2_cn + (pt2.y + c) * src2_cn + l]));
            }
        }
    }
    
    return nSum;
}
 
int SAD(Mat &src1, Mat &src2, Point pt1, Point pt2, int patch_size)
{
    // Range Check
    if ((pt1.x - patch_size) < || (pt2.x - patch_size) < || (pt1.x + patch_size) >= src1.rows ||
        (pt2.x + patch_size) >= src2.rows || (pt1.y - patch_size) < || (pt2.y - patch_size) < ||
        (pt1.y + patch_size) >= src1.cols || (pt2.y + patch_size) >= src2.cols)
        throw exception("SAD::Inavlid range");
 
    // Image Channel Check
    if (src1.channels() != src2.channels())
        throw exception("SAD::Image channel not same");
    
    int nSum = 0;
 
    unsigned char *src1_ptr = (unsigned char*)src1.data;
    unsigned char *src2_ptr = (unsigned char*)src2.data;
    int src1_cn = src1.channels();
    int src2_cn = src2.channels();
 
    for (int r = -patch_size; r <= patch_size; r++)
    {
        for (int c = -patch_size; c <= patch_size; c++)
        {
            for (int l = 0; l < src1_cn; l++)
            {
                nSum += abs((src1_ptr[(pt1.x + r) * src1.cols * src1_cn + (pt1.y + c) * src1_cn + l]) - (src2_ptr[(pt2.x + r) * src2.cols * src2_cn + (pt2.y + c) * src2_cn + l]));    
            }
        }
    }
 
    return nSum;
}
 
float NCC(Mat &src1, Mat &src2, Point pt1, Point pt2, int patch_size)
{
    // Range Check
    if ((pt1.x - patch_size) < || (pt2.x - patch_size) < || (pt1.x + patch_size) >= src1.rows ||
        (pt2.x + patch_size) >= src2.rows || (pt1.y - patch_size) < || (pt2.y - patch_size) < ||
        (pt1.y + patch_size) >= src1.cols || (pt2.y + patch_size) >= src2.cols)
        throw exception("NCC::Inavlid range");
 
    // Image Channel Check
    if (src1.channels() != src2.channels())
        throw exception("NCC::Image channel not same");
 
    // calcurate average, stendard deviation
    int nSum1 = 0, nSum2 = 0;
    int nSqr1 = 0, nSqr2 = 0;
    
    unsigned char *src1_ptr = (unsigned char*)src1.data;
    unsigned char *src2_ptr = (unsigned char*)src2.data;
    int src1_cn = src1.channels();
    int src2_cn = src2.channels();
        
    for (int r = -patch_size; r <= patch_size; r++)
    {
        for (int c = -patch_size; c <= patch_size; c++)
        {
            for (int l = 0; l < src1_cn; l++)
            {
                int t1 = src1_ptr[(pt1.x + r) * src1.cols * src1_cn + (pt1.y + c) * src1_cn + l];
                int t2 = src2_ptr[(pt2.x + r) * src2.cols * src2_cn + (pt2.y + c) * src2_cn + l];
 
                nSum1 += t1;
                nSum2 += t2;
                nSqr1 += t1 * t1;
                nSqr2 += t2 * t2;
            }
        }
    }
 
    int nPixels = (patch_size * + 1* (patch_size * + 1); // pixel num
    float fMean1 = (float)nSum1 / (float)nPixels;
    float fMean2 = (float)nSum2 / (float)nPixels;
    float fVar1 = (float)nSqr1 / (float)nPixels - (float)fMean1 * (float)fMean1;
    float fVar2 = (float)nSqr2 / (float)nPixels - (float)fMean2 * (float)fMean2;
 
    // NCC
    float fSumNCC = 0.0f;
 
    for (int r = -patch_size; r <= patch_size; r++)
    {
        for (int c = -patch_size; c <= patch_size; c++)
        {
            for (int l = 0; l < src1_cn; l++)
            {
                fSumNCC += (float)((src1_ptr[(pt1.x + r) * src1.cols * src1_cn + (pt1.y + c) * src1_cn + l]) - fMean1) 
                    * ((src2_ptr[(pt2.x + r) * src2.cols * src2_cn + (pt2.y + c) * src2_cn + l]) - fMean2);
            }
        }
    }
 
    return fSumNCC / (fVar1 * fVar2);
}
 
int main()
{
    Mat img, img2;
    img = imread("img/flower.jpg"1);
    img2 = imread("img/flower.jpg"1);
 
    int result_SSD = SSD(img, img2, Point(100100), Point(100100), 3);
    int result_SAD = SAD(img, img2, Point(100100), Point(100100), 3);
    float result_NCC = NCC(img, img2, Point(100100), Point(100100), 3);
 
    cout << "SSD = " << result_SSD << endl;
    cout << "SAD = " << result_SAD << endl;
    cout << "NCC = " << result_NCC << endl;
 
    namedWindow("image");
    imshow("image", img);
    waitKey();
 
    destroyAllWindows();
 
    return 0;
}
cs