Skip to content

Commit 88a351d

Browse files
committed
feature: add multi-channel support to ImageProximityFFT
1 parent 4daa0f6 commit 88a351d

File tree

3 files changed

+176
-89
lines changed

3 files changed

+176
-89
lines changed

C++/programs/ImageProximityFFT.cpp

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void ImageProximityFFT::PrepareFor(ImageBase& Source, Image& Template)
4343
size.Height = Source.Height();
4444

4545
if (m_image_sqsums == nullptr || m_image_sqsums->Width() < size.Width || m_image_sqsums->Height() < size.Height)
46-
m_image_sqsums = std::make_shared<TempImage>(*m_CL, size, SImage::F32, 1);
46+
m_image_sqsums = std::make_shared<TempImage>(*m_CL, size, SImage::F32, Source.NbChannels());
4747

4848

4949
// Size of the FFT input and output
@@ -81,62 +81,88 @@ void ImageProximityFFT::PrepareFor(ImageBase& Source, Image& Template)
8181
m_statistics.PrepareFor(Template);
8282
m_transform.PrepareFor(Source);
8383
m_fft.PrepareFor(*m_bigger_source, *m_source_spect);
84+
SelectProgram(Source).Build();
85+
SelectProgram(*m_source_spect).Build();
8486
}
8587

86-
void ImageProximityFFT::MatchTemplatePrepared_SQDIFF(int width, int hight, Image& Source, float templ_sqsum, Image& Dest)
88+
void ImageProximityFFT::MatchSquareDiff(int width, int hight, Image& Source, double * templ_sqsum, Image& Dest)
8789
{
88-
Check1Channel(Dest);
89-
Kernel(matchTemplatePreparedSQDIFF, In(Source), Out(Dest), width, hight, templ_sqsum, Source.Step(), Dest.Step(), Dest.Width(), Dest.Height());
90+
cl_float4 TemplateSqSum = {float(templ_sqsum[0]), float(templ_sqsum[1]), float(templ_sqsum[2]), float(templ_sqsum[3])};
91+
92+
Kernel(square_difference, In(Source), Out(Dest), Source.Step(), Dest.Width(), Dest.Height(), Dest.Step(),
93+
width, hight, TemplateSqSum);
9094
}
9195

92-
void ImageProximityFFT::MatchTemplatePrepared_SQDIFF_NORM(int width, int hight, Image& Source, float templ_sqsum, Image& Dest)
96+
void ImageProximityFFT::MatchSquareDiffNorm(int width, int hight, Image& Source, double * templ_sqsum, Image& Dest)
9397
{
94-
Check1Channel(Dest);
95-
Kernel(matchTemplatePreparedSQDIFF_NORM, In(Source), Out(Dest), width, hight, templ_sqsum, Source.Step(), Dest.Step(), Dest.Width(), Dest.Height());
98+
cl_float4 TemplateSqSum = {float(templ_sqsum[0]), float(templ_sqsum[1]), float(templ_sqsum[2]), float(templ_sqsum[3])};
99+
100+
Kernel(square_difference_norm, In(Source), Out(Dest), Source.Step(), Dest.Step(), Dest.Width(), Dest.Height(),
101+
width, hight, TemplateSqSum);
96102
}
97103

98-
void ImageProximityFFT::MatchTemplatePrepared_CCORR_NORM(int width, int hight, Image& Source, float templ_sqsum, Image& Dest)
104+
void ImageProximityFFT::MatchCrossCorrNorm(int width, int hight, Image& Source, double * templ_sqsum, Image& Dest)
99105
{
100-
Check1Channel(Dest);
101-
Kernel(matchTemplatePreparedCCORR_NORM, In(Source), Out(Dest), width, hight, templ_sqsum, Source.Step(), Dest.Step(), Dest.Width(), Dest.Height());
106+
cl_float4 TemplateSqSum = {float(templ_sqsum[0]), float(templ_sqsum[1]), float(templ_sqsum[2]), float(templ_sqsum[3])};
107+
108+
Kernel(crosscorr_norm, In(Source), Out(Dest), Source.Step(), Dest.Step(), Dest.Width(), Dest.Height(),
109+
width, hight, TemplateSqSum);
102110
}
103111

104112
void ImageProximityFFT::CrossCorr(Image& Source, Image& Template, Image& Dest)
105113
{
106-
CheckSameSize(Source, Dest);
107-
Check1Channel(Source);
108-
Check1Channel(Template);
109114
CheckFloat(Dest);
115+
CheckSameNbChannels(Source, Template);
116+
CheckSameNbChannels(Source, Dest);
117+
CheckSameSize(Source, Dest);
118+
119+
// Verify image size
120+
if (Template.Width() > Source.Width() || Template.Height() > Source.Height())
121+
throw cl::Error(CL_IMAGE_FORMAT_NOT_SUPPORTED, "The template image must be smaller than source image.");
110122

123+
// Verify image types
111124
if(!SameType(Source, Template))
112125
throw cl::Error(CL_IMAGE_FORMAT_MISMATCH, "The source image and the template image must be same type.");
113126

114-
Convolve(Source, Template, Dest);
127+
PrepareFor(Source, Template);
128+
129+
Convolve(Source, Template, Dest); // Computes the cross correlation using FFT
115130
}
116131

117132
void ImageProximityFFT::CrossCorr_Norm(Image& Source, Image& Template, Image& Dest)
118133
{
119-
CheckSameSize(Source, Dest);
120-
Check1Channel(Source);
121-
Check1Channel(Template);
122134
CheckFloat(Dest);
135+
CheckSameNbChannels(Source, Template);
136+
CheckSameNbChannels(Source, Dest);
137+
CheckSameSize(Source, Dest);
123138

139+
// Verify image size
140+
if (Template.Width() > Source.Width() || Template.Height() > Source.Height())
141+
throw cl::Error(CL_IMAGE_FORMAT_NOT_SUPPORTED, "The template image must be smaller than source image.");
142+
143+
// Verify image types
124144
if(!SameType(Source, Template))
125145
throw cl::Error(CL_IMAGE_FORMAT_MISMATCH, "The source image and the template image must be same type.");
126146

127147
PrepareFor(Source, Template);
128148

129149
m_integral.SqrIntegral(Source, *m_image_sqsums);
130150

131-
float templ_sqsum = static_cast<float>(m_statistics.SumSqr(Template));
151+
double templ_sqsum[4] = {0};
152+
m_statistics.SumSqr(Template, templ_sqsum);
132153

133-
Convolve(Source, Template, Dest);
154+
Convolve(Source, Template, Dest); // Computes the cross correlation using FFT
134155

135-
MatchTemplatePrepared_CCORR_NORM(Template.Width(), Template.Height(), *m_image_sqsums, templ_sqsum, Dest);
156+
MatchCrossCorrNorm(Template.Width(), Template.Height(), *m_image_sqsums, templ_sqsum, Dest);
136157
}
137158

138159
void ImageProximityFFT::SqrDistance(Image& Source, Image& Template, Image& Dest)
139160
{
161+
CheckFloat(Dest);
162+
CheckSameNbChannels(Source, Template);
163+
CheckSameNbChannels(Source, Dest);
164+
CheckSameSize(Source, Dest);
165+
140166
// Verify image size
141167
if (Template.Width() > Source.Width() || Template.Height() > Source.Height())
142168
throw cl::Error(CL_IMAGE_FORMAT_NOT_SUPPORTED, "The template image must be smaller than source image.");
@@ -145,23 +171,25 @@ void ImageProximityFFT::SqrDistance(Image& Source, Image& Template, Image& Dest)
145171
if(!SameType(Source, Template))
146172
throw cl::Error(CL_IMAGE_FORMAT_MISMATCH, "The source image and the template image must be same type.");
147173

148-
Check1Channel(Source);
149-
Check1Channel(Template);
150-
CheckFloat(Dest);
151-
152174
PrepareFor(Source, Template);
153175

154176
m_integral.SqrIntegral(Source, *m_image_sqsums);
155177

156-
float templ_sqsum = static_cast<float>(m_statistics.SumSqr(Template));
178+
double templ_sqsum[4] = {0};
179+
m_statistics.SumSqr(Template, templ_sqsum);
157180

158-
CrossCorr(Source, Template, Dest);
181+
Convolve(Source, Template, Dest); // Computes the cross correlation using FFT
159182

160-
MatchTemplatePrepared_SQDIFF(Template.Width(), Template.Height(), *m_image_sqsums, templ_sqsum, Dest);
183+
MatchSquareDiff(Template.Width(), Template.Height(), *m_image_sqsums, templ_sqsum, Dest);
161184
}
162185

163186
void ImageProximityFFT::SqrDistance_Norm(Image& Source, Image& Template, Image& Dest)
164187
{
188+
CheckFloat(Dest);
189+
CheckSameNbChannels(Source, Template);
190+
CheckSameNbChannels(Source, Dest);
191+
CheckSameSize(Source, Dest);
192+
165193
// Verify image size
166194
if (Template.Width() > Source.Width() || Template.Height() > Source.Height())
167195
throw cl::Error(CL_IMAGE_FORMAT_NOT_SUPPORTED, "The template image must be smaller than source image.");
@@ -170,18 +198,15 @@ void ImageProximityFFT::SqrDistance_Norm(Image& Source, Image& Template, Image&
170198
if(!SameType(Source, Template))
171199
throw cl::Error(CL_IMAGE_FORMAT_MISMATCH, "The source image and the template image must be same type.");
172200

173-
Check1Channel(Source);
174-
Check1Channel(Template);
175-
CheckFloat(Dest);
176-
177201
PrepareFor(Source, Template);
178202

179203
m_integral.SqrIntegral(Source, *m_image_sqsums);
180204

181-
float templ_sqsum = static_cast<float>(m_statistics.SumSqr(Template));
205+
double templ_sqsum[4] = {0};
206+
m_statistics.SumSqr(Template, templ_sqsum);
182207

183208
CrossCorr(Source, Template, Dest);
184-
MatchTemplatePrepared_SQDIFF_NORM(Template.Width(), Template.Height(), *m_image_sqsums, templ_sqsum, Dest);
209+
MatchSquareDiffNorm(Template.Width(), Template.Height(), *m_image_sqsums, templ_sqsum, Dest);
185210
}
186211

187212
void ImageProximityFFT::MulAndScaleSpectrums(Image& Source, Image& Template, Image& Dest, float scale)
@@ -210,47 +235,52 @@ void ImageProximityFFT::Convolve(Image& Source, Image& Template, Image& Dest)
210235
m_transform.SetAll(*m_bigger_template, 0);
211236
m_transform.SetAll(*m_bigger_source, 0);
212237

213-
// Copy the data from Source and Template in images that are F32 and are big enough
214-
Kernel(copy_offset, In(Source), Out(*m_bigger_source), Source.Step(), m_bigger_source->Step(),
215-
int(Template.Width()) / 2, int(Template.Height()) / 2, m_bigger_source->Width(), m_bigger_source->Height());
238+
for (uint i = 1; i <= Source.NbChannels(); i++)
239+
{
240+
// Copy the data from Source and Template in images that are F32 and are big enough
241+
Kernel(copy_offset, In(Source), Out(*m_bigger_source), Source.Step(), m_bigger_source->Step(),
242+
int(Template.Width()) / 2, int(Template.Height()) / 2, m_bigger_source->Width(), m_bigger_source->Height(), i);
243+
244+
Kernel(copy_offset, In(Template), Out(*m_bigger_template), Template.Step(), m_bigger_template->Step(),
245+
0, 0, m_bigger_template->Width(), m_bigger_template->Height(), i);
216246

217-
Kernel(copy_offset, In(Template), Out(*m_bigger_template), Template.Step(), m_bigger_template->Step(),
218-
0, 0, m_bigger_template->Width(), m_bigger_template->Height());
219247

248+
// Forward FFT of Source and Template
249+
m_fft.Forward(*m_bigger_source, *m_source_spect);
250+
m_fft.Forward(*m_bigger_template, *m_templ_spect);
220251

221-
// Forward FFT of Source and Template
222-
m_fft.Forward(*m_bigger_source, *m_source_spect);
223-
m_fft.Forward(*m_bigger_template, *m_templ_spect);
224252

253+
// We need to divide the values by the FFT area to get the proper
254+
float Area = float(m_bigger_source->Width() * m_bigger_source->Height());
225255

226-
// We need to divide the values by the FFT area to get the proper
227-
float Area = float(m_bigger_source->Width() * m_bigger_source->Height());
256+
// Do the convolution using pointwise product of the spectrums
257+
// See information here : http://en.wikipedia.org/wiki/Convolution_theorem
258+
MulAndScaleSpectrums(*m_source_spect, *m_templ_spect, *m_result_spect, 1 / Area);
228259

229-
// Do the convolution using pointwise product of the spectrums
230-
// See information here : http://en.wikipedia.org/wiki/Convolution_theorem
231-
MulAndScaleSpectrums(*m_source_spect, *m_templ_spect, *m_result_spect, 1 / Area);
232260

261+
// Inverse FFT to get the result of the convolution
262+
m_fft.Inverse(*m_result_spect, *m_bigger_source); // Reuse m_bigger_source image for the convolution result
233263

234-
// Inverse FFT to get the result of the convolution
235-
m_fft.Inverse(*m_result_spect, *m_bigger_source); // Reuse m_bigger_source image for the convolution result
236264

265+
// Copy the result to Dest
266+
Kernel_(*m_CL, SelectProgram(Dest), copy_result, m_bigger_source->FullRange(), LOCAL_RANGE,
267+
In(*m_bigger_source), Out(Dest), m_bigger_source->Step(), Dest.Step(), Dest.Width(), Dest.Height(), i);
268+
}
237269

238-
// Copy the result to Dest
239-
Kernel(copy_roi, In((*m_bigger_source)), Out(Dest), m_bigger_source->Step(), Dest.Step(), Dest.Width(), Dest.Height());
240270
}
241271

242272
#else // USE_CLFFT
243273

244274
void ImageProximityFFT::PrepareFor(ImageBase& , Image& )
245275
{ }
246276

247-
void ImageProximityFFT::MatchTemplatePrepared_SQDIFF(int , int , Image& , float , Image& )
277+
void ImageProximityFFT::MatchSquareDiff(int , int , Image& , float , Image& )
248278
{ }
249279

250-
void ImageProximityFFT::MatchTemplatePrepared_SQDIFF_NORM(int , int , Image& , float , Image& )
280+
void ImageProximityFFT::MatchSquareDiffNorm(int , int , Image& , float , Image& )
251281
{ }
252282

253-
void ImageProximityFFT::MatchTemplatePrepared_CCORR_NORM(int , int , Image& , float , Image& )
283+
void ImageProximityFFT::MatchCrossCorrNorm(int , int , Image& , float , Image& )
254284
{ }
255285

256286
void ImageProximityFFT::CrossCorr(Image& , Image& , Image& )

0 commit comments

Comments
 (0)