离散傅里叶变换(OpenCV4)
图像变换是许多图像处理技术的基础,为了有效和快速地对图像进行处理和分析,常常需要将原定义在图像空间的图像以某种形式转换到另外一个空间,并利用这些空间的特有性质更方便地进行一些处理,最后再变换为图像空间以得到所需效果。近年来,众多的图像变换方法不断涌现,从古老的傅里叶变换到余弦变换,直至小波变换,这些数学模型都对图像处理技术的发展有着不可磨灭的贡献。本篇随笔主要介绍离散傅里叶变换(关于傅里叶变换原理的更加详尽的介绍请看《傅里叶变换与图像处理》)。
离散傅里叶变换的原理
对一张图像使用傅里叶变换就是将它分解成正弦和余弦两部分,也就是将图像从空间域(spatial domain)转换到频率域(frequency domain)。二维图像的傅里叶变换的数学公式:
其中的f是空间域值,F是频率域值。转换后频率域值是复数。显示傅里叶变换之后的结果需要使用实数图像(real image)加虚数图像(complex image),或者幅度图像(magitude image)加相位图像(phase image)的形式。在实际的图像处理过程中,仅仅使用了幅度图像,因为幅度图像包含了原图像的几乎所有处理所需的集合信息。在频域里面,对于一幅图像,高频部分代表了图像的细节、纹理信息;低频部分代表了图像的轮廓信息。如果对一幅精细图像使用低通滤波器,那么滤波后的结果就只剩下轮廓了。这与信号处理的基本思想是相通的。如果图像受到的噪声恰好位于某个特定的“频率”范围内,则可以通过滤波器来恢复原来的图像。傅里叶变换在图像处理中可以做到图像增强与图像去噪、图像分割之边缘检测、图像的特征提取、图像压缩等。
OpenCV傅里叶变换所用函数
dft()函数的作用是对一维或二维浮点数数组进行正向或反向离散傅里叶变换。关于这个函数的更详尽的介绍请看OpenCV的官方文档。
C++ : void dft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0);
getOptimalDFTSize()函数返回给定向量尺寸的傅里叶最优尺寸大小。为了提高离散傅里叶变换的运行速度,需要扩充退选哪个,而具体扩充多少,就由这个函数计算得到。
C++ : int getOptimalDFTSize(int vecsize);
copyMakeBorder()函数的作用是扩充图像边界。
C++ : void copyMakeBorder(InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar& value = Scalar() );
magnitude()函数用于计算二维矢量的幅值。
C++ : void magnitude(InputArray x, InputArray y, OutputArray magnitude);
log()函数用于计算每个数组元素绝对值的自然对数。
C++ : void log(InputArray src, OutputArray dst);
其原理:dst(I)={x|log|src(I)| if src(I)≠0, C otherwise};
normalize()函数用于矩阵的归一化。
C++ : void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0, int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
演示示例:
#include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> using namespace cv; int main() { //【1】以灰度模式读取原始图像并显示 Mat srcImage = imread("1.png",0); if (!srcImage.data) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return false; } imshow("原始图像", srcImage); //【2】将输入图像延扩到最佳的尺寸,边界用0补充 int m = getOptimalDFTSize(srcImage.rows); int n = getOptimalDFTSize(srcImage.cols); //将添加的像素初始化为0. Mat padded; copyMakeBorder(srcImage, padded, 0, m - srcImage.rows, 0, n - srcImage.cols, BORDER_CONSTANT, Scalar::all(0)); //【3】为傅立叶变换的结果(实部和虚部)分配存储空间。 //将planes数组组合合并成一个多通道的数组complexI Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) }; Mat complexI; merge(planes, 2, complexI); //【4】进行就地离散傅里叶变换 dft(complexI, complexI); //【5】将复数转换为幅值,即=> log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) split(complexI, planes); // 将多通道数组complexI分离成几个单通道数组,planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude Mat magnitudeImage = planes[0]; //【6】进行对数尺度(logarithmic scale)缩放 magnitudeImage += Scalar::all(1); log(magnitudeImage, magnitudeImage);//求自然对数 //【8】归一化,用0到1之间的浮点值将矩阵变换为可视的图像格式 //此句代码的OpenCV2版为: //normalize(magnitudeImage, magnitudeImage, 0, 1, CV_MINMAX); //此句代码的OpenCV3版为: normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX); // 是这里的问题吗? //【9】显示效果图 imshow("频谱幅值", magnitudeImage); //【7】剪切和重分布幅度图象限 //若有奇数行或奇数列,进行频谱裁剪 magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2)); //重新排列傅立叶图像中的象限,使得原点位于图像中心 int cx = magnitudeImage.cols / 2; int cy = magnitudeImage.rows / 2; Mat q0(magnitudeImage, Rect(0, 0, cx, cy)); // ROI区域的左上 Mat q1(magnitudeImage, Rect(cx, 0, cx, cy)); // ROI区域的右上 Mat q2(magnitudeImage, Rect(0, cy, cx, cy)); // ROI区域的左下 Mat q3(magnitudeImage, Rect(cx, cy, cx, cy)); // ROI区域的右下 //交换象限(左上与右下进行交换) Mat tmp; q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); //交换象限(右上与左下进行交换) q1.copyTo(tmp); q2.copyTo(q1); tmp.copyTo(q2); //【9】显示效果图 imshow("原点频谱幅值", magnitudeImage); waitKey(); return 0; }
运行示例:
二维离散傅里叶变换的性质
离散傅里叶变换建立了函数在空间域到频率域之间的转换关系。这里简单地介绍一下二维离散傅里叶变换的基本性质:
1. 可分离性:一个二维离散傅里叶变换可以通过先后两次运用一维傅里叶变换来实现,即先沿f(x,y)的列方向求一维离散傅里叶变换得到F(x,v),再对F(x,v)沿行的方向求一维离散傅里叶变换得到F(u,v): 其中的过程如图示:
二维离散傅里叶反变换的分离过程和正变换的过程相似。
2. 平移性:傅里叶变换的平移性是指将f(x,y)乘以一个指数项相当于将其二维离散傅里叶变换F(u,v)的频域中心移动到新的位置。这个性质可以表示为:
从上式可知,对f(x,y)的平移不影响其傅里叶变换的幅值,只是在频域中发生了相移而已。反之,当频域中的F(u,v)产生相移时,相应的f(x,y)在空域中也只是发生了相移而幅值不变。那么如果要把图像的频谱原点从起始点(0,0)移到图像的中心点(N/2,N/2),需要乘上一个什么因子呢?其简单的运算过程如下:
这个因子就是(-1)x+y。
3. 周期性:傅里叶正变换和反变换均以N为周期,即F(u,v)=F(u+N,v)=F(u,v+N)=F(u+N,v+N)。
4. 共轭对称性:如果f(x,y)是实函数,则它的傅里叶变换具有共轭对称性——F(u,v)=F*(-u,-v),|F(u,v)|=|F(-u,-v)|。式中F*(u,v)是F(u,v)的复共轭。
5. 旋转不变形:对于旋转的描述,使用极坐标是非常方便的。所以这里引入极坐标使,
则f(x,y)和F(u,v)分别表示f(r,θ)和F(ω,φ)。容易得到公式,f(r,θ+θ0)↔F(ω,φ+θ0)。公式表明这样一个结论——如果f(x,y)在空域旋转θ0角度,则相应的傅里叶变换F(u,v)在频域上也旋转同一角度θ0。
6. 分配性和比例性:傅里叶变换的分配性表明它对于加法可以分配,而乘法则不行,如下式所示,
而傅里叶变换的比例性则表明对于两个标量a和b,有,
上式表明,在空间比例尺度的展宽,对应于在频域比例尺度的压缩,其幅值也减少为原来的1/|ab|。
实验一 实现二维傅里叶变换和逆变换
【实验目的】
通过实验,深入理解和掌握图像处理的基本技术,提高动手实践能力。
【实验环境】
MATLAB 和 VC++ 任选其一。(博主可能在某些地方使用 Python 进行实验)
【实验内容】
1)观察离散傅里叶频谱,并演示二维离散傅里叶变换的的主要性质(如平移性、旋转不变性、比例性、中心化)。
2)给出快速FFT变换与傅里叶变换的时间比较,并对图像进行反变换。
【实验步骤】
实验思路:原先博主想通过修改 OpenCV4 的 dft() 函数来演示傅里叶变换的主要性质的,但是博主在看了一下该函数的实现之后,觉得修改的代价比较大因此此篇博文不采用这种方法。下面请欣赏一下dft()函数的实现,由于 Intel 公司在该源文件的开头有相关的许可声明并且该函数的实现也调用了其他函数,所有本文将包含该函数的一个源文件给展示出来(注:安装了OpenCV的同学们,可以在***\opencv\sources\modules\core\src路径下,找到dxt.cpp。dft()函数的声明从3315行开始)。
1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 22 // * Redistribution's in binary form must reproduce the above copyright notice, 23 // this list of conditions and the following disclaimer in the documentation 24 // and/or other materials provided with the distribution. 25 // 26 // * The name of Intel Corporation may not be used to endorse or promote products 27 // derived from this software without specific prior written permission. 28 // 29 // This software is provided by the copyright holders and contributors "as is" and 30 // any express or implied warranties, including, but not limited to, the implied 31 // warranties of merchantability and fitness for a particular purpose are disclaimed. 32 // In no event shall the Intel Corporation or contributors be liable for any direct, 33 // indirect, incidental, special, exemplary, or consequential damages 34 // (including, but not limited to, procurement of substitute goods or services; 35 // loss of use, data, or profits; or business interruption) however caused 36 // and on any theory of liability, whether in contract, strict liability, 37 // or tort (including negligence or otherwise) arising in any way out of 38 // the use of this software, even if advised of the possibility of such damage. 39 // 40 //M*/ 41 42 #include "precomp.hpp" 43 #include "opencv2/core/opencl/runtime/opencl_clamdfft.hpp" 44 #include "opencv2/core/opencl/runtime/opencl_core.hpp" 45 #include "opencl_kernels_core.hpp" 46 #include <map> 47 48 namespace cv 49 { 50 51 // On Win64 optimized versions of DFT and DCT fail the tests (fixed in VS2010) 52 #if defined _MSC_VER && !defined CV_ICC && defined _M_X64 && _MSC_VER < 1600 53 # pragma optimize("", off) 54 # pragma warning(disable: 4748) 55 #endif 56 57 #if IPP_VERSION_X100 >= 710 58 #define USE_IPP_DFT 1 59 #else 60 #undef USE_IPP_DFT 61 #endif 62 63 /****************************************************************************************\ 64 Discrete Fourier Transform 65 \****************************************************************************************/ 66 67 #define CV_MAX_LOCAL_DFT_SIZE (1 << 15) 68 69 static unsigned char bitrevTab[] = 70 { 71 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, 72 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, 73 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, 74 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, 75 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, 76 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, 77 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, 78 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, 79 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, 80 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, 81 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, 82 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, 83 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, 84 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, 85 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, 86 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff 87 }; 88 89 static const double DFTTab[][2] = 90 { 91 { 1.00000000000000000, 0.00000000000000000 }, 92 {-1.00000000000000000, 0.00000000000000000 }, 93 { 0.00000000000000000, 1.00000000000000000 }, 94 { 0.70710678118654757, 0.70710678118654746 }, 95 { 0.92387953251128674, 0.38268343236508978 }, 96 { 0.98078528040323043, 0.19509032201612825 }, 97 { 0.99518472667219693, 0.09801714032956060 }, 98 { 0.99879545620517241, 0.04906767432741802 }, 99 { 0.99969881869620425, 0.02454122852291229 }, 100 { 0.99992470183914450, 0.01227153828571993 }, 101 { 0.99998117528260111, 0.00613588464915448 }, 102 { 0.99999529380957619, 0.00306795676296598 }, 103 { 0.99999882345170188, 0.00153398018628477 }, 104 { 0.99999970586288223, 0.00076699031874270 }, 105 { 0.99999992646571789, 0.00038349518757140 }, 106 { 0.99999998161642933, 0.00019174759731070 }, 107 { 0.99999999540410733, 0.00009587379909598 }, 108 { 0.99999999885102686, 0.00004793689960307 }, 109 { 0.99999999971275666, 0.00002396844980842 }, 110 { 0.99999999992818922, 0.00001198422490507 }, 111 { 0.99999999998204725, 0.00000599211245264 }, 112 { 0.99999999999551181, 0.00000299605622633 }, 113 { 0.99999999999887801, 0.00000149802811317 }, 114 { 0.99999999999971945, 0.00000074901405658 }, 115 { 0.99999999999992983, 0.00000037450702829 }, 116 { 0.99999999999998246, 0.00000018725351415 }, 117 { 0.99999999999999567, 0.00000009362675707 }, 118 { 0.99999999999999889, 0.00000004681337854 }, 119 { 0.99999999999999978, 0.00000002340668927 }, 120 { 0.99999999999999989, 0.00000001170334463 }, 121 { 1.00000000000000000, 0.00000000585167232 }, 122 { 1.00000000000000000, 0.00000000292583616 } 123 }; 124 125 #define BitRev(i,shift) \ 126 ((int)((((unsigned)bitrevTab[(i)&255] << 24)+ \ 127 ((unsigned)bitrevTab[((i)>> 8)&255] << 16)+ \ 128 ((unsigned)bitrevTab[((i)>>16)&255] << 8)+ \ 129 ((unsigned)bitrevTab[((i)>>24)])) >> (shift))) 130 131 static int 132 DFTFactorize( int n, int* factors ) 133 { 134 int nf = 0, f, i, j; 135 136 if( n <= 5 ) 137 { 138 factors[0] = n; 139 return 1; 140 } 141 142 f = (((n - 1)^n)+1) >> 1; 143 if( f > 1 ) 144 { 145 factors[nf++] = f; 146 n = f == n ? 1 : n/f; 147 } 148 149 for( f = 3; n > 1; ) 150 { 151 int d = n/f; 152 if( d*f == n ) 153 { 154 factors[nf++] = f; 155 n = d; 156 } 157 else 158 { 159 f += 2; 160 if( f*f > n ) 161 break; 162 } 163 } 164 165 if( n > 1 ) 166 factors[nf++] = n; 167 168 f = (factors[0] & 1) == 0; 169 for( i = f; i < (nf+f)/2; i++ ) 170 CV_SWAP( factors[i], factors[nf-i-1+f], j ); 171 172 return nf; 173 } 174 175 static void 176 DFTInit( int n0, int nf, const int* factors, int* itab, int elem_size, void* _wave, int inv_itab ) 177 { 178 int digits[34], radix[34]; 179 int n = factors[0], m = 0; 180 int* itab0 = itab; 181 int i, j, k; 182 Complex<double> w, w1; 183 double t; 184 185 if( n0 <= 5 ) 186 { 187 itab[0] = 0; 188 itab[n0-1] = n0-1; 189 190 if( n0 != 4 ) 191 { 192 for( i = 1; i < n0-1; i++ ) 193 itab[i] = i; 194 } 195 else 196 { 197 itab[1] = 2; 198 itab[2] = 1; 199 } 200 if( n0 == 5 ) 201 { 202 if( elem_size == sizeof(Complex<double>) ) 203 ((Complex<double>*)_wave)[0] = Complex<double>(1.,0.); 204 else 205 ((Complex<float>*)_wave)[0] = Complex<float>(1.f,0.f); 206 } 207 if( n0 != 4 ) 208 return; 209 m = 2; 210 } 211 else 212 { 213 // radix[] is initialized from index 'nf' down to zero 214 assert (nf < 34); 215 radix[nf] = 1; 216 digits[nf] = 0; 217 for( i = 0; i < nf; i++ ) 218 { 219 digits[i] = 0; 220 radix[nf-i-1] = radix[nf-i]*factors[nf-i-1]; 221 } 222 223 if( inv_itab && factors[0] != factors[nf-1] ) 224 itab = (int*)_wave; 225 226 if( (n & 1) == 0 ) 227 { 228 int a = radix[1], na2 = n*a>>1, na4 = na2 >> 1; 229 for( m = 0; (unsigned)(1 << m) < (unsigned)n; m++ ) 230 ; 231 if( n <= 2 ) 232 { 233 itab[0] = 0; 234 itab[1] = na2; 235 } 236 else if( n <= 256 ) 237 { 238 int shift = 10 - m; 239 for( i = 0; i <= n - 4; i += 4 ) 240 { 241 j = (bitrevTab[i>>2]>>shift)*a; 242 itab[i] = j; 243 itab[i+1] = j + na2; 244 itab[i+2] = j + na4; 245 itab[i+3] = j + na2 + na4; 246 } 247 } 248 else 249 { 250 int shift = 34 - m; 251 for( i = 0; i < n; i += 4 ) 252 { 253 int i4 = i >> 2; 254 j = BitRev(i4,shift)*a; 255 itab[i] = j; 256 itab[i+1] = j + na2; 257 itab[i+2] = j + na4; 258 itab[i+3] = j + na2 + na4; 259 } 260 } 261 262 digits[1]++; 263 264 if( nf >= 2 ) 265 { 266 for( i = n, j = radix[2]; i < n0; ) 267 { 268 for( k = 0; k < n; k++ ) 269 itab[i+k] = itab[k] + j; 270 if( (i += n) >= n0 ) 271 break; 272 j += radix[2]; 273 for( k = 1; ++digits[k] >= factors[k]; k++ ) 274 { 275 digits[k] = 0; 276 j += radix[k+2] - radix[k]; 277 } 278 } 279 } 280 } 281 else 282 { 283 for( i = 0, j = 0;; ) 284 { 285 itab[i] = j; 286 if( ++i >= n0 ) 287 break; 288 j += radix[1]; 289 for( k = 0; ++digits[k] >= factors[k]; k++ ) 290 { 291 digits[k] = 0; 292 j += radix[k+2] - radix[k]; 293 } 294 } 295 } 296 297 if( itab != itab0 ) 298 { 299 itab0[0] = 0; 300 for( i = n0 & 1; i < n0; i += 2 ) 301 { 302 int k0 = itab[i]; 303 int k1 = itab[i+1]; 304 itab0[k0] = i; 305 itab0[k1] = i+1; 306 } 307 } 308 } 309 310 if( (n0 & (n0-1)) == 0 ) 311 { 312 w.re = w1.re = DFTTab[m][0]; 313 w.im = w1.im = -DFTTab[m][1]; 314 } 315 else 316 { 317 t = -CV_PI*2/n0; 318 w.im = w1.im = sin(t); 319 w.re = w1.re = std::sqrt(1. - w1.im*w1.im); 320 } 321 n = (n0+1)/2; 322 323 if( elem_size == sizeof(Complex<double>) ) 324 { 325 Complex<double>* wave = (Complex<double>*)_wave; 326 327 wave[0].re = 1.; 328 wave[0].im = 0.; 329 330 if( (n0 & 1) == 0 ) 331 { 332 wave[n].re = -1.; 333 wave[n].im = 0; 334 } 335 336 for( i = 1; i < n; i++ ) 337 { 338 wave[i] = w; 339 wave[n0-i].re = w.re; 340 wave[n0-i].im = -w.im; 341 342 t = w.re*w1.re - w.im*w1.im; 343 w.im = w.re*w1.im + w.im*w1.re; 344 w.re = t; 345 } 346 } 347 else 348 { 349 Complex<float>* wave = (Complex<float>*)_wave; 350 assert( elem_size == sizeof(Complex<float>) ); 351 352 wave[0].re = 1.f; 353 wave[0].im = 0.f; 354 355 if( (n0 & 1) == 0 ) 356 { 357 wave[n].re = -1.f; 358 wave[n].im = 0.f; 359 } 360 361 for( i = 1; i < n; i++ ) 362 { 363 wave[i].re = (float)w.re; 364 wave[i].im = (float)w.im; 365 wave[n0-i].re = (float)w.re; 366 wave[n0-i].im = (float)-w.im; 367 368 t = w.re*w1.re - w.im*w1.im; 369 w.im = w.re*w1.im + w.im*w1.re; 370 w.re = t; 371 } 372 } 373 } 374 375 template<typename T> struct DFT_VecR4 376 { 377 int operator()(Complex<T>*, int, int, int&, const Complex<T>*) const { return 1; } 378 }; 379 380 #if CV_SSE3 381 382 // optimized radix-4 transform 383 template<> struct DFT_VecR4<float> 384 { 385 int operator()(Complex<float>* dst, int N, int n0, int& _dw0, const Complex<float>* wave) const 386 { 387 int n = 1, i, j, nx, dw, dw0 = _dw0; 388 __m128 z = _mm_setzero_ps(), x02=z, x13=z, w01=z, w23=z, y01, y23, t0, t1; 389 Cv32suf t; t.i = 0x80000000; 390 __m128 neg0_mask = _mm_load_ss(&t.f); 391 __m128 neg3_mask = _mm_shuffle_ps(neg0_mask, neg0_mask, _MM_SHUFFLE(0,1,2,3)); 392 393 for( ; n*4 <= N; ) 394 { 395 nx = n; 396 n *= 4; 397 dw0 /= 4; 398 399 for( i = 0; i < n0; i += n ) 400 { 401 Complexf *v0, *v1; 402 403 v0 = dst + i; 404 v1 = v0 + nx*2; 405 406 x02 = _mm_loadl_pi(x02, (const __m64*)&v0[0]); 407 x13 = _mm_loadl_pi(x13, (const __m64*)&v0[nx]); 408 x02 = _mm_loadh_pi(x02, (const __m64*)&v1[0]); 409 x13 = _mm_loadh_pi(x13, (const __m64*)&v1[nx]); 410 411 y01 = _mm_add_ps(x02, x13); 412 y23 = _mm_sub_ps(x02, x13); 413 t1 = _mm_xor_ps(_mm_shuffle_ps(y01, y23, _MM_SHUFFLE(2,3,3,2)), neg3_mask); 414 t0 = _mm_movelh_ps(y01, y23); 415 y01 = _mm_add_ps(t0, t1); 416 y23 = _mm_sub_ps(t0, t1); 417 418 _mm_storel_pi((__m64*)&v0[0], y01); 419 _mm_storeh_pi((__m64*)&v0[nx], y01); 420 _mm_storel_pi((__m64*)&v1[0], y23); 421 _mm_storeh_pi((__m64*)&v1[nx], y23); 422 423 for( j = 1, dw = dw0; j < nx; j++, dw += dw0 ) 424 { 425 v0 = dst + i + j; 426 v1 = v0 + nx*2; 427 428 x13 = _mm_loadl_pi(x13, (const __m64*)&v0[nx]); 429 w23 = _mm_loadl_pi(w23, (const __m64*)&wave[dw*2]); 430 x13 = _mm_loadh_pi(x13, (const __m64*)&v1[nx]); // x1, x3 = r1 i1 r3 i3 431 w23 = _mm_loadh_pi(w23, (const __m64*)&wave[dw*3]); // w2, w3 = wr2 wi2 wr3 wi3 432 433 t0 = _mm_mul_ps(_mm_moveldup_ps(x13), w23); 434 t1 = _mm_mul_ps(_mm_movehdup_ps(x13), _mm_shuffle_ps(w23, w23, _MM_SHUFFLE(2,3,0,1))); 435 x13 = _mm_addsub_ps(t0, t1); 436 // re(x1*w2), im(x1*w2), re(x3*w3), im(x3*w3) 437 x02 = _mm_loadl_pi(x02, (const __m64*)&v1[0]); // x2 = r2 i2 438 w01 = _mm_loadl_pi(w01, (const __m64*)&wave[dw]); // w1 = wr1 wi1 439 x02 = _mm_shuffle_ps(x02, x02, _MM_SHUFFLE(0,0,1,1)); 440 w01 = _mm_shuffle_ps(w01, w01, _MM_SHUFFLE(1,0,0,1)); 441 x02 = _mm_mul_ps(x02, w01); 442 x02 = _mm_addsub_ps(x02, _mm_movelh_ps(x02, x02)); 443 // re(x0) im(x0) re(x2*w1), im(x2*w1) 444 x02 = _mm_loadl_pi(x02, (const __m64*)&v0[0]); 445 446 y01 = _mm_add_ps(x02, x13); 447 y23 = _mm_sub_ps(x02, x13); 448 t1 = _mm_xor_ps(_mm_shuffle_ps(y01, y23, _MM_SHUFFLE(2,3,3,2)), neg3_mask); 449 t0 = _mm_movelh_ps(y01, y23); 450 y01 = _mm_add_ps(t0, t1); 451 y23 = _mm_sub_ps(t0, t1); 452 453 _mm_storel_pi((__m64*)&v0[0], y01); 454 _mm_storeh_pi((__m64*)&v0[nx], y01); 455 _mm_storel_pi((__m64*)&v1[0], y23); 456 _mm_storeh_pi((__m64*)&v1[nx], y23); 457 } 458 } 459 } 460 461 _dw0 = dw0; 462 return n; 463 } 464 }; 465 466 #endif 467 468 #ifdef USE_IPP_DFT 469 static IppStatus ippsDFTFwd_CToC( const Complex<float>* src, Complex<float>* dst, 470 const void* spec, uchar* buf) 471 { 472 return CV_INSTRUMENT_FUN_IPP(ippsDFTFwd_CToC_32fc, (const Ipp32fc*)src, (Ipp32fc*)dst, 473 (const IppsDFTSpec_C_32fc*)spec, buf); 474 } 475 476 static IppStatus ippsDFTFwd_CToC( const Complex<double>* src, Complex<double>* dst, 477 const void* spec, uchar* buf) 478 { 479 return CV_INSTRUMENT_FUN_IPP(ippsDFTFwd_CToC_64fc, (const Ipp64fc*)src, (Ipp64fc*)dst, 480 (const IppsDFTSpec_C_64fc*)spec, buf); 481 } 482 483 static IppStatus ippsDFTInv_CToC( const Complex<float>* src, Complex<float>* dst, 484 const void* spec, uchar* buf) 485 { 486 return CV_INSTRUMENT_FUN_IPP(ippsDFTInv_CToC_32fc, (const Ipp32fc*)src, (Ipp32fc*)dst, 487 (const IppsDFTSpec_C_32fc*)spec, buf); 488 } 489 490 static IppStatus ippsDFTInv_CToC( const Complex<double>* src, Complex<double>* dst, 491 const void* spec, uchar* buf) 492 { 493 return CV_INSTRUMENT_FUN_IPP(ippsDFTInv_CToC_64fc, (const Ipp64fc*)src, (Ipp64fc*)dst, 494 (const IppsDFTSpec_C_64fc*)spec, buf); 495 } 496 497 static IppStatus ippsDFTFwd_RToPack( const float* src, float* dst, 498 const void* spec, uchar* buf) 499 { 500 return CV_INSTRUMENT_FUN_IPP(ippsDFTFwd_RToPack_32f, src, dst, (const IppsDFTSpec_R_32f*)spec, buf); 501 } 502 503 static IppStatus ippsDFTFwd_RToPack( const double* src, double* dst, 504 const void* spec, uchar* buf) 505 { 506 return CV_INSTRUMENT_FUN_IPP(ippsDFTFwd_RToPack_64f, src, dst, (const IppsDFTSpec_R_64f*)spec, buf); 507 } 508 509 static IppStatus ippsDFTInv_PackToR( const float* src, float* dst, 510 const void* spec, uchar* buf) 511 { 512 return CV_INSTRUMENT_FUN_IPP(ippsDFTInv_PackToR_32f, src, dst, (const IppsDFTSpec_R_32f*)spec, buf); 513 } 514 515 static IppStatus ippsDFTInv_PackToR( const double* src, double* dst, 516 const void* spec, uchar* buf) 517 { 518 return CV_INSTRUMENT_FUN_IPP(ippsDFTInv_PackToR_64f, src, dst, (const IppsDFTSpec_R_64f*)spec, buf); 519 } 520 #endif 521 522 struct OcvDftOptions; 523 524 typedef void (*DFTFunc)(const OcvDftOptions & c, const void* src, void* dst); 525 526 struct OcvDftOptions { 527 int nf; 528 int *factors; 529 double scale; 530 531 int* itab; 532 void* wave; 533 int tab_size; 534 int n; 535 536 bool isInverse; 537 bool noPermute; 538 bool isComplex; 539 540 bool haveSSE3; 541 542 DFTFunc dft_func; 543 bool useIpp; 544 545 #ifdef USE_IPP_DFT 546 uchar* ipp_spec; 547 uchar* ipp_work; 548 #endif 549 550 OcvDftOptions() 551 { 552 nf = 0; 553 factors = 0; 554 scale = 0; 555 itab = 0; 556 wave = 0; 557 tab_size = 0; 558 n = 0; 559 isInverse = false; 560 noPermute = false; 561 isComplex = false; 562 useIpp = false; 563 #ifdef USE_IPP_DFT 564 ipp_spec = 0; 565 ipp_work = 0; 566 #endif 567 dft_func = 0; 568 haveSSE3 = checkHardwareSupport(CV_CPU_SSE3); 569 } 570 }; 571 572 // mixed-radix complex discrete Fourier transform: double-precision version 573 template<typename T> static void 574 DFT(const OcvDftOptions & c, const Complex<T>* src, Complex<T>* dst) 575 { 576 static const T sin_120 = (T)0.86602540378443864676372317075294; 577 static const T fft5_2 = (T)0.559016994374947424102293417182819; 578 static const T fft5_3 = (T)-0.951056516295153572116439333379382; 579 static const T fft5_4 = (T)-1.538841768587626701285145288018455; 580 static const T fft5_5 = (T)0.363271264002680442947733378740309; 581 582 const Complex<T>* wave = (Complex<T>*)c.wave; 583 const int * itab = c.itab; 584 585 int n = c.n; 586 int f_idx, nx; 587 int inv = c.isInverse; 588 int dw0 = c.tab_size, dw; 589 int i, j, k; 590 Complex<T> t; 591 T scale = (T)c.scale; 592 593 if( c.useIpp ) 594 { 595 #ifdef USE_IPP_DFT 596 if( !inv ) 597 { 598 if (ippsDFTFwd_CToC( src, dst, c.ipp_spec, c.ipp_work ) >= 0) 599 { 600 CV_IMPL_ADD(CV_IMPL_IPP); 601 return; 602 } 603 } 604 else 605 { 606 if (ippsDFTInv_CToC( src, dst, c.ipp_spec, c.ipp_work ) >= 0) 607 { 608 CV_IMPL_ADD(CV_IMPL_IPP); 609 return; 610 } 611 } 612 setIppErrorStatus(); 613 #endif 614 } 615 616 int tab_step = c.tab_size == n ? 1 : c.tab_size == n*2 ? 2 : c.tab_size/n; 617 618 // 0. shuffle data 619 if( dst != src ) 620 { 621 assert( !c.noPermute ); 622 if( !inv ) 623 { 624 for( i = 0; i <= n - 2; i += 2, itab += 2*tab_step ) 625 { 626 int k0 = itab[0], k1 = itab[tab_step]; 627 assert( (unsigned)k0 < (unsigned)n && (unsigned)k1 < (unsigned)n ); 628 dst[i] = src[k0]; dst[i+1] = src[k1]; 629 } 630 631 if( i < n ) 632 dst[n-1] = src[n-1]; 633 } 634 else 635 { 636 for( i = 0; i <= n - 2; i += 2, itab += 2*tab_step ) 637 { 638 int k0 = itab[0], k1 = itab[tab_step]; 639 assert( (unsigned)k0 < (unsigned)n && (unsigned)k1 < (unsigned)n ); 640 t.re = src[k0].re; t.im = -src[k0].im; 641 dst[i] = t; 642 t.re = src[k1].re; t.im = -src[k1].im; 643 dst[i+1] = t; 644 } 645 646 if( i < n ) 647 { 648 t.re = src[n-1].re; t.im = -src[n-1].im; 649 dst[i] = t; 650 } 651 } 652 } 653 else 654 { 655 if( !c.noPermute ) 656 { 657 CV_Assert( c.factors[0] == c.factors[c.nf-1] ); 658 if( c.nf == 1 ) 659 { 660 if( (n & 3) == 0 ) 661 { 662 int n2 = n/2; 663 Complex<T>* dsth = dst + n2; 664 665 for( i = 0; i < n2; i += 2, itab += tab_step*2 ) 666 { 667 j = itab[0]; 668 assert( (unsigned)j < (unsigned)n2 ); 669 670 CV_SWAP(dst[i+1], dsth[j], t); 671 if( j > i ) 672 { 673 CV_SWAP(dst[i], dst[j], t); 674 CV_SWAP(dsth[i+1], dsth[j+1], t); 675 } 676 } 677 } 678 // else do nothing 679 } 680 else 681 { 682 for( i = 0; i < n; i++, itab += tab_step ) 683 { 684 j = itab[0]; 685 assert( (unsigned)j < (unsigned)n ); 686 if( j > i ) 687 CV_SWAP(dst[i], dst[j], t); 688 } 689 } 690 } 691 692 if( inv ) 693 { 694 for( i = 0; i <= n - 2; i += 2 ) 695 { 696 T t0 = -dst[i].im; 697 T t1 = -dst[i+1].im; 698 dst[i].im = t0; dst[i+1].im = t1; 699 } 700 701 if( i < n ) 702 dst[n-1].im = -dst[n-1].im; 703 } 704 } 705 706 n = 1; 707 // 1. power-2 transforms 708 if( (c.factors[0] & 1) == 0 ) 709 { 710 if( c.factors[0] >= 4 && c.haveSSE3) 711 { 712 DFT_VecR4<T> vr4; 713 n = vr4(dst, c.factors[0], c.n, dw0, wave); 714 } 715 716 // radix-4 transform 717 for( ; n*4 <= c.factors[0]; ) 718 { 719 nx = n; 720 n *= 4; 721 dw0 /= 4; 722 723 for( i = 0; i < c.n; i += n ) 724 { 725 Complex<T> *v0, *v1; 726 T r0, i0, r1, i1, r2, i2, r3, i3, r4, i4; 727 728 v0 = dst + i; 729 v1 = v0 + nx*2; 730 731 r0 = v1[0].re; i0 = v1[0].im; 732 r4 = v1[nx].re; i4 = v1[nx].im; 733 734 r1 = r0 + r4; i1 = i0 + i4; 735 r3 = i0 - i4; i3 = r4 - r0; 736 737 r2 = v0[0].re; i2 = v0[0].im; 738 r4 = v0[nx].re; i4 = v0[nx].im; 739 740 r0 = r2 + r4; i0 = i2 + i4; 741 r2 -= r4; i2 -= i4; 742 743 v0[0].re = r0 + r1; v0[0].im = i0 + i1; 744 v1[0].re = r0 - r1; v1[0].im = i0 - i1; 745 v0[nx].re = r2 + r3; v0[nx].im = i2 + i3; 746 v1[nx].re = r2 - r3; v1[nx].im = i2 - i3; 747 748 for( j = 1, dw = dw0; j < nx; j++, dw += dw0 ) 749 { 750 v0 = dst + i + j; 751 v1 = v0 + nx*2; 752 753 r2 = v0[nx].re*wave[dw*2].re - v0[nx].im*wave[dw*2].im; 754 i2 = v0[nx].re*wave[dw*2].im + v0[nx].im*wave[dw*2].re; 755 r0 = v1[0].re*wave[dw].im + v1[0].im*wave[dw].re; 756 i0 = v1[0].re*wave[dw].re - v1[0].im*wave[dw].im; 757 r3 = v1[nx].re*wave[dw*3].im + v1[nx].im*wave[dw*3].re; 758 i3 = v1[nx].re*wave[dw*3].re - v1[nx].im*wave[dw*3].im; 759 760 r1 = i0 + i3; i1 = r0 + r3; 761 r3 = r0 - r3; i3 = i3 - i0; 762 r4 = v0[0].re; i4 = v0[0].im; 763 764 r0 = r4 + r2; i0 = i4 + i2; 765 r2 = r4 - r2; i2 = i4 - i2; 766 767 v0[0].re = r0 + r1; v0[0].im = i0 + i1; 768 v1[0].re = r0 - r1; v1[0].im = i0 - i1; 769 v0[nx].re = r2 + r3; v0[nx].im = i2 + i3; 770 v1[nx].re = r2 - r3; v1[nx].im = i2 - i3; 771 } 772 } 773 } 774 775 for( ; n < c.factors[0]; ) 776 { 777 // do the remaining radix-2 transform 778 nx = n; 779 n *= 2; 780 dw0 /= 2; 781 782 for( i = 0; i < c.n; i += n ) 783 { 784 Complex<T>* v = dst + i; 785 T r0 = v[0].re + v[nx].re; 786 T i0 = v[0].im + v[nx].im; 787 T r1 = v[0].re - v[nx].re; 788 T i1 = v[0].im - v[nx].im; 789 v[0].re = r0; v[0].im = i0; 790 v[nx].re = r1; v[nx].im = i1; 791 792 for( j = 1, dw = dw0; j < nx; j++, dw += dw0 ) 793 { 794 v = dst + i + j; 795 r1 = v[nx].re*wave[dw].re - v[nx].im*wave[dw].im; 796 i1 = v[nx].im*wave[dw].re + v[nx].re*wave[dw].im; 797 r0 = v[0].re; i0 = v[0].im; 798 799 v[0].re = r0 + r1; v[0].im = i0 + i1; 800 v[nx].re = r0 - r1; v[nx].im = i0 - i1; 801 } 802 } 803 } 804 } 805 806 // 2. all the other transforms 807 for( f_idx = (c.factors[0]&1) ? 0 : 1; f_idx < c.nf; f_idx++ ) 808 { 809 int factor = c.factors[f_idx]; 810 nx = n; 811 n *= factor; 812 dw0 /= factor; 813 814 if( factor == 3 ) 815 { 816 // radix-3 817 for( i = 0; i < c.n; i += n ) 818 { 819 Complex<T>* v = dst + i; 820 821 T r1 = v[nx].re + v[nx*2].re; 822 T i1 = v[nx].im + v[nx*2].im; 823 T r0 = v[0].re; 824 T i0 = v[0].im; 825 T r2 = sin_120*(v[nx].im - v[nx*2].im); 826 T i2 = sin_120*(v[nx*2].re - v[nx].re); 827 v[0].re = r0 + r1; v[0].im = i0 + i1; 828 r0 -= (T)0.5*r1; i0 -= (T)0.5*i1; 829 v[nx].re = r0 + r2; v[nx].im = i0 + i2; 830 v[nx*2].re = r0 - r2; v[nx*2].im = i0 - i2; 831 832 for( j = 1, dw = dw0; j < nx; j++, dw += dw0 ) 833 { 834 v = dst + i + j; 835 r0 = v[nx].re*wave[dw].re - v[nx].im*wave[dw].im; 836 i0 = v[nx].re*wave[dw].im + v[nx].im*wave[dw].re; 837 i2 = v[nx*2].re*wave[dw*2].re - v[nx*2].im*wave[dw*2].im; 838 r2 = v[nx*2].re*wave[dw*2].im + v[nx*2].im*wave[dw*2].re; 839 r1 = r0 + i2; i1 = i0 + r2; 840 841 r2 = sin_120*(i0 - r2); i2 = sin_120*(i2 - r0); 842 r0 = v[0].re; i0 = v[0].im; 843 v[0].re = r0 + r1; v[0].im = i0 + i1; 844 r0 -= (T)0.5*r1; i0 -= (T)0.5*i1; 845 v[nx].re = r0 + r2; v[nx].im = i0 + i2; 846 v[nx*2].re = r0 - r2; v[nx*2].im = i0 - i2; 847 } 848 } 849 } 850 else if( factor == 5 ) 851 { 852 // radix-5 853 for( i = 0; i < c.n; i += n ) 854 { 855 for( j = 0, dw = 0; j < nx; j++, dw += dw0 ) 856 { 857 Complex<T>* v0 = dst + i + j; 858 Complex<T>* v1 = v0 + nx*2; 859 Complex<T>* v2 = v1 + nx*2; 860 861 T r0, i0, r1, i1, r2, i2, r3, i3, r4, i4, r5, i5; 862 863 r3 = v0[nx].re*wave[dw].re - v0[nx].im*wave[dw].im; 864 i3 = v0[nx].re*wave[dw].im + v0[nx].im*wave[dw].re; 865 r2 = v2[0].re*wave[dw*4].re - v2[0].im*wave[dw*4].im; 866 i2 = v2[0].re*wave[dw*4].im + v2[0].im*wave[dw*4].re; 867 868 r1 = r3 + r2; i1 = i3 + i2; 869 r3 -= r2; i3 -= i2; 870 871 r4 = v1[nx].re*wave[dw*3].re - v1[nx].im*wave[dw*3].im; 872 i4 = v1[nx].re*wave[dw*3].im + v1[nx].im*wave[dw*3].re; 873 r0 = v1[0].re*wave[dw*2].re - v1[0].im*wave[dw*2].im; 874 i0 = v1[0].re*wave[dw*2].im + v1[0].im*wave[dw*2].re; 875 876 r2 = r4 + r0; i2 = i4 + i0; 877 r4 -= r0; i4 -= i0; 878 879 r0 = v0[0].re; i0 = v0[0].im; 880 r5 = r1 + r2; i5 = i1 + i2; 881 882 v0[0].re = r0 + r5; v0[0].im = i0 + i5; 883 884 r0 -= (T)0.25*r5; i0 -= (T)0.25*i5; 885 r1 = fft5_2*(r1 - r2); i1 = fft5_2*(i1 - i2); 886 r2 = -fft5_3*(i3 + i4); i2 = fft5_3*(r3 + r4); 887 888 i3 *= -fft5_5; r3 *= fft5_5; 889 i4 *= -fft5_4; r4 *= fft5_4; 890 891 r5 = r2 + i3; i5 = i2 + r3; 892 r2 -= i4; i2 -= r4; 893 894 r3 = r0 + r1; i3 = i0 + i1; 895 r0 -= r1; i0 -= i1; 896 897 v0[nx].re = r3 + r2; v0[nx].im = i3 + i2; 898 v2[0].re = r3 - r2; v2[0].im = i3 - i2; 899 900 v1[0].re = r0 + r5; v1[0].im = i0 + i5; 901 v1[nx].re = r0 - r5; v1[nx].im = i0 - i5; 902 } 903 } 904 } 905 else 906 { 907 // radix-"factor" - an odd number 908 int p, q, factor2 = (factor - 1)/2; 909 int d, dd, dw_f = c.tab_size/factor; 910 AutoBuffer<Complex<T> > buf(factor2 * 2); 911 Complex<T>* a = buf.data(); 912 Complex<T>* b = a + factor2; 913 914 for( i = 0; i < c.n; i += n ) 915 { 916 for( j = 0, dw = 0; j < nx; j++, dw += dw0 ) 917 { 918 Complex<T>* v = dst + i + j; 919 Complex<T> v_0 = v[0]; 920 Complex<T> vn_0 = v_0; 921 922 if( j == 0 ) 923 { 924 for( p = 1, k = nx; p <= factor2; p++, k += nx ) 925 { 926 T r0 = v[k].re + v[n-k].re; 927 T i0 = v[k].im - v[n-k].im; 928 T r1 = v[k].re - v[n-k].re; 929 T i1 = v[k].im + v[n-k].im; 930 931 vn_0.re += r0; vn_0.im += i1; 932 a[p-1].re = r0; a[p-1].im = i0; 933 b[p-1].re = r1; b[p-1].im = i1; 934 } 935 } 936 else 937 { 938 const Complex<T>* wave_ = wave + dw*factor; 939 d = dw; 940 941 for( p = 1, k = nx; p <= factor2; p++, k += nx, d += dw ) 942 { 943 T r2 = v[k].re*wave[d].re - v[k].im*wave[d].im; 944 T i2 = v[k].re*wave[d].im + v[k].im*wave[d].re; 945 946 T r1 = v[n-k].re*wave_[-d].re - v[n-k].im*wave_[-d].im; 947 T i1 = v[n-k].re*wave_[-d].im + v[n-k].im*wave_[-d].re; 948 949 T r0 = r2 + r1; 950 T i0 = i2 - i1; 951 r1 = r2 - r1; 952 i1 = i2 + i1; 953 954 vn_0.re += r0; vn_0.im += i1; 955 a[p-1].re = r0; a[p-1].im = i0; 956 b[p-1].re = r1; b[p-1].im = i1; 957 } 958 } 959 960 v[0] = vn_0; 961 962 for( p = 1, k = nx; p <= factor2; p++, k += nx ) 963 { 964 Complex<T> s0 = v_0, s1 = v_0; 965 d = dd = dw_f*p; 966 967 for( q = 0; q < factor2; q++ ) 968 { 969 T r0 = wave[d].re * a[q].re; 970 T i0 = wave[d].im * a[q].im; 971 T r1 = wave[d].re * b[q].im; 972 T i1 = wave[d].im * b[q].re; 973 974 s1.re += r0 + i0; s0.re += r0 - i0; 975 s1.im += r1 - i1; s0.im += r1 + i1; 976 977 d += dd; 978 d -= -(d >= c.tab_size) & c.tab_size; 979 } 980 981 v[k] = s0; 982 v[n-k] = s1; 983 } 984 } 985 } 986 } 987 } 988 989 if( scale != 1 ) 990 { 991 T re_scale = scale, im_scale = scale; 992 if( inv ) 993 im_scale = -im_scale; 994 995 for( i = 0; i < c.n; i++ ) 996 { 997 T t0 = dst[i].re*re_scale; 998 T t1 = dst[i].im*im_scale; 999 dst[i].re = t0; 1000 dst[i].im = t1; 1001 } 1002 } 1003 else if( inv ) 1004 { 1005 for( i = 0; i <= c.n - 2; i += 2 ) 1006 { 1007 T t0 = -dst[i].im; 1008 T t1 = -dst[i+1].im; 1009 dst[i].im = t0; 1010 dst[i+1].im = t1; 1011 } 1012 1013 if( i < c.n ) 1014 dst[c.n-1].im = -dst[c.n-1].im; 1015 } 1016 } 1017 1018 1019 /* FFT of real vector 1020 output vector format: 1021 re(0), re(1), im(1), ... , re(n/2-1), im((n+1)/2-1) [, re((n+1)/2)] OR ... 1022 re(0), 0, re(1), im(1), ..., re(n/2-1), im((n+1)/2-1) [, re((n+1)/2), 0] */ 1023 template<typename T> static void 1024 RealDFT(const OcvDftOptions & c, const T* src, T* dst) 1025 { 1026 int n = c.n; 1027 int complex_output = c.isComplex; 1028 T scale = (T)c.scale; 1029 int j; 1030 dst += complex_output; 1031 1032 if( c.useIpp ) 1033 { 1034 #ifdef USE_IPP_DFT 1035 if (ippsDFTFwd_RToPack( src, dst, c.ipp_spec, c.ipp_work ) >=0) 1036 { 1037 if( complex_output ) 1038 { 1039 dst[-1] = dst[0]; 1040 dst[0] = 0; 1041 if( (n & 1) == 0 ) 1042 dst[n] = 0; 1043 } 1044 CV_IMPL_ADD(CV_IMPL_IPP); 1045 return; 1046 } 1047 setIppErrorStatus(); 1048 #endif 1049 } 1050 assert( c.tab_size == n ); 1051 1052 if( n == 1 ) 1053 { 1054 dst[0] = src[0]*scale; 1055 } 1056 else if( n == 2 ) 1057 { 1058 T t = (src[0] + src[1])*scale; 1059 dst[1] = (src[0] - src[1])*scale; 1060 dst[0] = t; 1061 } 1062 else if( n & 1 ) 1063 { 1064 dst -= complex_output; 1065 Complex<T>* _dst = (Complex<T>*)dst; 1066 _dst[0].re = src[0]*scale; 1067 _dst[0].im = 0; 1068 for( j = 1; j < n; j += 2 ) 1069 { 1070 T t0 = src[c.itab[j]]*scale; 1071 T t1 = src[c.itab[j+1]]*scale; 1072 _dst[j].re = t0; 1073 _dst[j].im = 0; 1074 _dst[j+1].re = t1; 1075 _dst[j+1].im = 0; 1076 } 1077 OcvDftOptions sub_c = c; 1078 sub_c.isComplex = false; 1079 sub_c.isInverse = false; 1080 sub_c.noPermute = true; 1081 sub_c.scale = 1.; 1082 DFT(sub_c, _dst, _dst); 1083 if( !complex_output ) 1084 dst[1] = dst[0]; 1085 } 1086 else 1087 { 1088 T t0, t; 1089 T h1_re, h1_im, h2_re, h2_im; 1090 T scale2 = scale*(T)0.5; 1091 int n2 = n >> 1; 1092 1093 c.factors[0] >>= 1; 1094 1095 OcvDftOptions sub_c = c; 1096 sub_c.factors += (c.factors[0] == 1); 1097 sub_c.nf -= (c.factors[0] == 1); 1098 sub_c.isComplex = false; 1099 sub_c.isInverse = false; 1100 sub_c.noPermute = false; 1101 sub_c.scale = 1.; 1102 sub_c.n = n2; 1103 1104 DFT(sub_c, (Complex<T>*)src, (Complex<T>*)dst); 1105 1106 c.factors[0] <<= 1; 1107 1108 t = dst[0] - dst[1]; 1109 dst[0] = (dst[0] + dst[1])*scale; 1110 dst[1] = t*scale; 1111 1112 t0 = dst[n2]; 1113 t = dst[n-1]; 1114 dst[n-1] = dst[1]; 1115 1116 const Complex<T> *wave = (const Complex<T>*)c.wave; 1117 1118 for( j = 2, wave++; j < n2; j += 2, wave++ ) 1119 { 1120 /* calc odd */ 1121 h2_re = scale2*(dst[j+1] + t); 1122 h2_im = scale2*(dst[n-j] - dst[j]); 1123 1124 /* calc even */ 1125 h1_re = scale2*(dst[j] + dst[n-j]); 1126 h1_im = scale2*(dst[j+1] - t); 1127 1128 /* rotate */ 1129 t = h2_re*wave->re - h2_im*wave->im; 1130 h2_im = h2_re*wave->im + h2_im*wave->re; 1131 h2_re = t; 1132 t = dst[n-j-1]; 1133 1134 dst[j-1] = h1_re + h2_re; 1135 dst[n-j-1] = h1_re - h2_re; 1136 dst[j] = h1_im + h2_im; 1137 dst[n-j] = h2_im - h1_im; 1138 } 1139 1140 if( j <= n2 ) 1141 { 1142 dst[n2-1] = t0*scale; 1143 dst[n2] = -t*scale; 1144 } 1145 } 1146 1147 if( complex_output && ((n & 1) == 0 || n == 1)) 1148 { 1149 dst[-1] = dst[0]; 1150 dst[0] = 0; 1151 if( n > 1 ) 1152 dst[n] = 0; 1153 } 1154 } 1155 1156 /* Inverse FFT of complex conjugate-symmetric vector 1157 input vector format: 1158 re[0], re[1], im[1], ... , re[n/2-1], im[n/2-1], re[n/2] OR 1159 re(0), 0, re(1), im(1), ..., re(n/2-1), im((n+1)/2-1) [, re((n+1)/2), 0] */ 1160 template<typename T> static void 1161 CCSIDFT(const OcvDftOptions & c, const T* src, T* dst) 1162 { 1163 int n = c.n; 1164 int complex_input = c.isComplex; 1165 int j, k; 1166 T scale = (T)c.scale; 1167 T save_s1 = 0.; 1168 T t0, t1, t2, t3, t; 1169 1170 assert( c.tab_size == n ); 1171 1172 if( complex_input ) 1173 { 1174 assert( src != dst ); 1175 save_s1 = src[1]; 1176 ((T*)src)[1] = src[0]; 1177 src++; 1178 } 1179 if( c.useIpp ) 1180 { 1181 #ifdef USE_IPP_DFT 1182 if (ippsDFTInv_PackToR( src, dst, c.ipp_spec, c.ipp_work ) >=0) 1183 { 1184 if( complex_input ) 1185 ((T*)src)[0] = (T)save_s1; 1186 CV_IMPL_ADD(CV_IMPL_IPP); 1187 return; 1188 } 1189 1190 setIppErrorStatus(); 1191 #endif 1192 } 1193 if( n == 1 ) 1194 { 1195 dst[0] = (T)(src[0]*scale); 1196 } 1197 else if( n == 2 ) 1198 { 1199 t = (src[0] + src[1])*scale; 1200 dst[1] = (src[0] - src[1])*scale; 1201 dst[0] = t; 1202 } 1203 else if( n & 1 ) 1204 { 1205 Complex<T>* _src = (Complex<T>*)(src-1); 1206 Complex<T>* _dst = (Complex<T>*)dst; 1207 1208 _dst[0].re = src[0]; 1209 _dst[0].im = 0; 1210 1211 int n2 = (n+1) >> 1; 1212 1213 for( j = 1; j < n2; j++ ) 1214 { 1215 int k0 = c.itab[j], k1 = c.itab[n-j]; 1216 t0 = _src[j].re; t1 = _src[j].im; 1217 _dst[k0].re = t0; _dst[k0].im = -t1; 1218 _dst[k1].re = t0; _dst[k1].im = t1; 1219 } 1220 1221 OcvDftOptions sub_c = c; 1222 sub_c.isComplex = false; 1223 sub_c.isInverse = false; 1224 sub_c.noPermute = true; 1225 sub_c.scale = 1.; 1226 sub_c.n = n; 1227 1228 DFT(sub_c, _dst, _dst); 1229 dst[0] *= scale; 1230 for( j = 1; j < n; j += 2 ) 1231 { 1232 t0 = dst[j*2]*scale; 1233 t1 = dst[j*2+2]*scale; 1234 dst[j] = t0; 1235 dst[j+1] = t1; 1236 } 1237 } 1238 else 1239 { 1240 int inplace = src == dst; 1241 const Complex<T>* w = (const Complex<T>*)c.wave; 1242 1243 t = src[1]; 1244 t0 = (src[0] + src[n-1]); 1245 t1 = (src[n-1] - src[0]); 1246 dst[0] = t0; 1247 dst[1] = t1; 1248 1249 int n2 = (n+1) >> 1; 1250 1251 for( j = 2, w++; j < n2; j += 2, w++ ) 1252 { 1253 T h1_re, h1_im, h2_re, h2_im; 1254 1255 h1_re = (t + src[n-j-1]); 1256 h1_im = (src[j] - src[n-j]); 1257 1258 h2_re = (t - src[n-j-1]); 1259 h2_im = (src[j] + src[n-j]); 1260 1261 t = h2_re*w->re + h2_im*w->im; 1262 h2_im = h2_im*w->re - h2_re*w->im; 1263 h2_re = t; 1264 1265 t = src[j+1]; 1266 t0 = h1_re - h2_im; 1267 t1 = -h1_im - h2_re; 1268 t2 = h1_re + h2_im; 1269 t3 = h1_im - h2_re; 1270 1271 if( inplace ) 1272 { 1273 dst[j] = t0; 1274 dst[j+1] = t1; 1275 dst[n-j] = t2; 1276 dst[n-j+1]= t3; 1277 } 1278 else 1279 { 1280 int j2 = j >> 1; 1281 k = c.itab[j2]; 1282 dst[k] = t0; 1283 dst[k+1] = t1; 1284 k = c.itab[n2-j2]; 1285 dst[k] = t2; 1286 dst[k+1]= t3; 1287 } 1288 } 1289 1290 if( j <= n2 ) 1291 { 1292 t0 = t*2; 1293 t1 = src[n2]*2; 1294 1295 if( inplace ) 1296 { 1297 dst[n2] = t0; 1298 dst[n2+1] = t1; 1299 } 1300 else 1301 { 1302 k = c.itab[n2]; 1303 dst[k*2] = t0; 1304 dst[k*2+1] = t1; 1305 } 1306 } 1307 1308 c.factors[0] >>= 1; 1309 1310 OcvDftOptions sub_c = c; 1311 sub_c.factors += (c.factors[0] == 1); 1312 sub_c.nf -= (c.factors[0] == 1); 1313 sub_c.isComplex = false; 1314 sub_c.isInverse = false; 1315 sub_c.noPermute = !inplace; 1316 sub_c.scale = 1.; 1317 sub_c.n = n2; 1318 1319 DFT(sub_c, (Complex<T>*)dst, (Complex<T>*)dst); 1320 1321 c.factors[0] <<= 1; 1322 1323 for( j = 0; j < n; j += 2 ) 1324 { 1325 t0 = dst[j]*scale; 1326 t1 = dst[j+1]*(-scale); 1327 dst[j] = t0; 1328 dst[j+1] = t1; 1329 } 1330 } 1331 if( complex_input ) 1332 ((T*)src)[0] = (T)save_s1; 1333 } 1334 1335 static void 1336 CopyColumn( const uchar* _src, size_t src_step, 1337 uchar* _dst, size_t dst_step, 1338 int len, size_t elem_size ) 1339 { 1340 int i, t0, t1; 1341 const int* src = (const int*)_src; 1342 int* dst = (int*)_dst; 1343 src_step /= sizeof(src[0]); 1344 dst_step /= sizeof(dst[0]); 1345 1346 if( elem_size == sizeof(int) ) 1347 { 1348 for( i = 0; i < len; i++, src += src_step, dst += dst_step ) 1349 dst[0] = src[0]; 1350 } 1351 else if( elem_size == sizeof(int)*2 ) 1352 { 1353 for( i = 0; i < len; i++, src += src_step, dst += dst_step ) 1354 { 1355 t0 = src[0]; t1 = src[1]; 1356 dst[0] = t0; dst[1] = t1; 1357 } 1358 } 1359 else if( elem_size == sizeof(int)*4 ) 1360 { 1361 for( i = 0; i < len; i++, src += src_step, dst += dst_step ) 1362 { 1363 t0 = src[0]; t1 = src[1]; 1364 dst[0] = t0; dst[1] = t1; 1365 t0 = src[2]; t1 = src[3]; 1366 dst[2] = t0; dst[3] = t1; 1367 } 1368 } 1369 } 1370 1371 1372 static void 1373 CopyFrom2Columns( const uchar* _src, size_t src_step, 1374 uchar* _dst0, uchar* _dst1, 1375 int len, size_t elem_size ) 1376 { 1377 int i, t0, t1; 1378 const int* src = (const int*)_src; 1379 int* dst0 = (int*)_dst0; 1380 int* dst1 = (int*)_dst1; 1381 src_step /= sizeof(src[0]); 1382 1383 if( elem_size == sizeof(int) ) 1384 { 1385 for( i = 0; i < len; i++, src += src_step ) 1386 { 1387 t0 = src[0]; t1 = src[1]; 1388 dst0[i] = t0; dst1[i] = t1; 1389 } 1390 } 1391 else if( elem_size == sizeof(int)*2 ) 1392 { 1393 for( i = 0; i < len*2; i += 2, src += src_step ) 1394 { 1395 t0 = src[0]; t1 = src[1]; 1396 dst0[i] = t0; dst0[i+1] = t1; 1397 t0 = src[2]; t1 = src[3]; 1398 dst1[i] = t0; dst1[i+1] = t1; 1399 } 1400 } 1401 else if( elem_size == sizeof(int)*4 ) 1402 { 1403 for( i = 0; i < len*4; i += 4, src += src_step ) 1404 { 1405 t0 = src[0]; t1 = src[1]; 1406 dst0[i] = t0; dst0[i+1] = t1; 1407 t0 = src[2]; t1 = src[3]; 1408 dst0[i+2] = t0; dst0[i+3] = t1; 1409 t0 = src[4]; t1 = src[5]; 1410 dst1[i] = t0; dst1[i+1] = t1; 1411 t0 = src[6]; t1 = src[7]; 1412 dst1[i+2] = t0; dst1[i+3] = t1; 1413 } 1414 } 1415 } 1416 1417 1418 static void 1419 CopyTo2Columns( const uchar* _src0, const uchar* _src1, 1420 uchar* _dst, size_t dst_step, 1421 int len, size_t elem_size ) 1422 { 1423 int i, t0, t1; 1424 const int* src0 = (const int*)_src0; 1425 const int* src1 = (const int*)_src1; 1426 int* dst = (int*)_dst; 1427 dst_step /= sizeof(dst[0]); 1428 1429 if( elem_size == sizeof(int) ) 1430 { 1431 for( i = 0; i < len; i++, dst += dst_step ) 1432 { 1433 t0 = src0[i]; t1 = src1[i]; 1434 dst[0] = t0; dst[1] = t1; 1435 } 1436 } 1437 else if( elem_size == sizeof(int)*2 ) 1438 { 1439 for( i = 0; i < len*2; i += 2, dst += dst_step ) 1440 { 1441 t0 = src0[i]; t1 = src0[i+1]; 1442 dst[0] = t0; dst[1] = t1; 1443 t0 = src1[i]; t1 = src1[i+1]; 1444 dst[2] = t0; dst[3] = t1; 1445 } 1446 } 1447 else if( elem_size == sizeof(int)*4 ) 1448 { 1449 for( i = 0; i < len*4; i += 4, dst += dst_step ) 1450 { 1451 t0 = src0[i]; t1 = src0[i+1]; 1452 dst[0] = t0; dst[1] = t1; 1453 t0 = src0[i+2]; t1 = src0[i+3]; 1454 dst[2] = t0; dst[3] = t1; 1455 t0 = src1[i]; t1 = src1[i+1]; 1456 dst[4] = t0; dst[5] = t1; 1457 t0 = src1[i+2]; t1 = src1[i+3]; 1458 dst[6] = t0; dst[7] = t1; 1459 } 1460 } 1461 } 1462 1463 1464 static void 1465 ExpandCCS( uchar* _ptr, int n, int elem_size ) 1466 { 1467 int i; 1468 if( elem_size == (int)sizeof(float) ) 1469 { 1470 float* p = (float*)_ptr; 1471 for( i = 1; i < (n+1)/2; i++ ) 1472 { 1473 p[(n-i)*2] = p[i*2-1]; 1474 p[(n-i)*2+1] = -p[i*2]; 1475 } 1476 if( (n & 1) == 0 ) 1477 { 1478 p[n] = p[n-1]; 1479 p[n+1] = 0.f; 1480 n--; 1481 } 1482 for( i = n-1; i > 0; i-- ) 1483 p[i+1] = p[i]; 1484 p[1] = 0.f; 1485 } 1486 else 1487 { 1488 double* p = (double*)_ptr; 1489 for( i = 1; i < (n+1)/2; i++ ) 1490 { 1491 p[(n-i)*2] = p[i*2-1]; 1492 p[(n-i)*2+1] = -p[i*2]; 1493 } 1494 if( (n & 1) == 0 ) 1495 { 1496 p[n] = p[n-1]; 1497 p[n+1] = 0.f; 1498 n--; 1499 } 1500 for( i = n-1; i > 0; i-- ) 1501 p[i+1] = p[i]; 1502 p[1] = 0.f; 1503 } 1504 } 1505 1506 static void DFT_32f(const OcvDftOptions & c, const Complexf* src, Complexf* dst) 1507 { 1508 DFT(c, src, dst); 1509 } 1510 1511 static void DFT_64f(const OcvDftOptions & c, const Complexd* src, Complexd* dst) 1512 { 1513 DFT(c, src, dst); 1514 } 1515 1516 1517 static void RealDFT_32f(const OcvDftOptions & c, const float* src, float* dst) 1518 { 1519 RealDFT(c, src, dst); 1520 } 1521 1522 static void RealDFT_64f(const OcvDftOptions & c, const double* src, double* dst) 1523 { 1524 RealDFT(c, src, dst); 1525 } 1526 1527 static void CCSIDFT_32f(const OcvDftOptions & c, const float* src, float* dst) 1528 { 1529 CCSIDFT(c, src, dst); 1530 } 1531 1532 static void CCSIDFT_64f(const OcvDftOptions & c, const double* src, double* dst) 1533 { 1534 CCSIDFT(c, src, dst); 1535 } 1536 1537 } 1538 1539 #ifdef USE_IPP_DFT 1540 typedef IppStatus (CV_STDCALL* IppDFTGetSizeFunc)(int, int, IppHintAlgorithm, int*, int*, int*); 1541 typedef IppStatus (CV_STDCALL* IppDFTInitFunc)(int, int, IppHintAlgorithm, void*, uchar*); 1542 #endif 1543 1544 namespace cv 1545 { 1546 #if defined USE_IPP_DFT 1547 1548 typedef IppStatus (CV_STDCALL* ippiDFT_C_Func)(const Ipp32fc*, int, Ipp32fc*, int, const IppiDFTSpec_C_32fc*, Ipp8u*); 1549 typedef IppStatus (CV_STDCALL* ippiDFT_R_Func)(const Ipp32f* , int, Ipp32f* , int, const IppiDFTSpec_R_32f* , Ipp8u*); 1550 1551 template <typename Dft> 1552 class Dft_C_IPPLoop_Invoker : public ParallelLoopBody 1553 { 1554 public: 1555 1556 Dft_C_IPPLoop_Invoker(const uchar * _src, size_t _src_step, uchar * _dst, size_t _dst_step, int _width, 1557 const Dft& _ippidft, int _norm_flag, bool *_ok) : 1558 ParallelLoopBody(), 1559 src(_src), src_step(_src_step), dst(_dst), dst_step(_dst_step), width(_width), 1560 ippidft(_ippidft), norm_flag(_norm_flag), ok(_ok) 1561 { 1562 *ok = true; 1563 } 1564 1565 virtual void operator()(const Range& range) const CV_OVERRIDE 1566 { 1567 IppStatus status; 1568 Ipp8u* pBuffer = 0; 1569 Ipp8u* pMemInit= 0; 1570 int sizeBuffer=0; 1571 int sizeSpec=0; 1572 int sizeInit=0; 1573 1574 IppiSize srcRoiSize = {width, 1}; 1575 1576 status = ippiDFTGetSize_C_32fc(srcRoiSize, norm_flag, ippAlgHintNone, &sizeSpec, &sizeInit, &sizeBuffer ); 1577 if ( status < 0 ) 1578 { 1579 *ok = false; 1580 return; 1581 } 1582 1583 IppiDFTSpec_C_32fc* pDFTSpec = (IppiDFTSpec_C_32fc*)CV_IPP_MALLOC( sizeSpec ); 1584 1585 if ( sizeInit > 0 ) 1586 pMemInit = (Ipp8u*)CV_IPP_MALLOC( sizeInit ); 1587 1588 if ( sizeBuffer > 0 ) 1589 pBuffer = (Ipp8u*)CV_IPP_MALLOC( sizeBuffer ); 1590 1591 status = ippiDFTInit_C_32fc( srcRoiSize, norm_flag, ippAlgHintNone, pDFTSpec, pMemInit ); 1592 1593 if ( sizeInit > 0 ) 1594 ippFree( pMemInit ); 1595 1596 if ( status < 0 ) 1597 { 1598 ippFree( pDFTSpec ); 1599 if ( sizeBuffer > 0 ) 1600 ippFree( pBuffer ); 1601 *ok = false; 1602 return; 1603 } 1604 1605 for( int i = range.start; i < range.end; ++i) 1606 if(!ippidft((Ipp32fc*)(src + src_step * i), src_step, (Ipp32fc*)(dst + dst_step * i), dst_step, 1607 pDFTSpec, (Ipp8u*)pBuffer)) 1608 { 1609 *ok = false; 1610 } 1611 1612 if ( sizeBuffer > 0 ) 1613 ippFree( pBuffer ); 1614 1615 ippFree( pDFTSpec ); 1616 CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); 1617 } 1618 1619 private: 1620 const uchar * src; 1621 size_t src_step; 1622 uchar * dst; 1623 size_t dst_step; 1624 int width; 1625 const Dft& ippidft; 1626 int norm_flag; 1627 bool *ok; 1628 1629 const Dft_C_IPPLoop_Invoker& operator= (const Dft_C_IPPLoop_Invoker&); 1630 }; 1631 1632 template <typename Dft> 1633 class Dft_R_IPPLoop_Invoker : public ParallelLoopBody 1634 { 1635 public: 1636 1637 Dft_R_IPPLoop_Invoker(const uchar * _src, size_t _src_step, uchar * _dst, size_t _dst_step, int _width, 1638 const Dft& _ippidft, int _norm_flag, bool *_ok) : 1639 ParallelLoopBody(), 1640 src(_src), src_step(_src_step), dst(_dst), dst_step(_dst_step), width(_width), 1641 ippidft(_ippidft), norm_flag(_norm_flag), ok(_ok) 1642 { 1643 *ok = true; 1644 } 1645 1646 virtual void operator()(const Range& range) const CV_OVERRIDE 1647 { 1648 IppStatus status; 1649 Ipp8u* pBuffer = 0; 1650 Ipp8u* pMemInit= 0; 1651 int sizeBuffer=0; 1652 int sizeSpec=0; 1653 int sizeInit=0; 1654 1655 IppiSize srcRoiSize = {width, 1}; 1656 1657 status = ippiDFTGetSize_R_32f(srcRoiSize, norm_flag, ippAlgHintNone, &sizeSpec, &sizeInit, &sizeBuffer ); 1658 if ( status < 0 ) 1659 { 1660 *ok = false; 1661 return; 1662 } 1663 1664 IppiDFTSpec_R_32f* pDFTSpec = (IppiDFTSpec_R_32f*)CV_IPP_MALLOC( sizeSpec ); 1665 1666 if ( sizeInit > 0 ) 1667 pMemInit = (Ipp8u*)CV_IPP_MALLOC( sizeInit ); 1668 1669 if ( sizeBuffer > 0 ) 1670 pBuffer = (Ipp8u*)CV_IPP_MALLOC( sizeBuffer ); 1671 1672 status = ippiDFTInit_R_32f( srcRoiSize, norm_flag, ippAlgHintNone, pDFTSpec, pMemInit ); 1673 1674 if ( sizeInit > 0 ) 1675 ippFree( pMemInit ); 1676 1677 if ( status < 0 ) 1678 { 1679 ippFree( pDFTSpec ); 1680 if ( sizeBuffer > 0 ) 1681 ippFree( pBuffer ); 1682 *ok = false; 1683 return; 1684 } 1685 1686 for( int i = range.start; i < range.end; ++i) 1687 if(!ippidft((float*)(src + src_step * i), src_step, (float*)(dst + dst_step * i), dst_step, 1688 pDFTSpec, (Ipp8u*)pBuffer)) 1689 { 1690 *ok = false; 1691 } 1692 1693 if ( sizeBuffer > 0 ) 1694 ippFree( pBuffer ); 1695 1696 ippFree( pDFTSpec ); 1697 CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); 1698 } 1699 1700 private: 1701 const uchar * src; 1702 size_t src_step; 1703 uchar * dst; 1704 size_t dst_step; 1705 int width; 1706 const Dft& ippidft; 1707 int norm_flag; 1708 bool *ok; 1709 1710 const Dft_R_IPPLoop_Invoker& operator= (const Dft_R_IPPLoop_Invoker&); 1711 }; 1712 1713 template <typename Dft> 1714 bool Dft_C_IPPLoop(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, const Dft& ippidft, int norm_flag) 1715 { 1716 bool ok; 1717 parallel_for_(Range(0, height), Dft_C_IPPLoop_Invoker<Dft>(src, src_step, dst, dst_step, width, ippidft, norm_flag, &ok), (width * height)/(double)(1<<16) ); 1718 return ok; 1719 } 1720 1721 template <typename Dft> 1722 bool Dft_R_IPPLoop(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, const Dft& ippidft, int norm_flag) 1723 { 1724 bool ok; 1725 parallel_for_(Range(0, height), Dft_R_IPPLoop_Invoker<Dft>(src, src_step, dst, dst_step, width, ippidft, norm_flag, &ok), (width * height)/(double)(1<<16) ); 1726 return ok; 1727 } 1728 1729 struct IPPDFT_C_Functor 1730 { 1731 IPPDFT_C_Functor(ippiDFT_C_Func _func) : ippiDFT_CToC_32fc_C1R(_func){} 1732 1733 bool operator()(const Ipp32fc* src, size_t srcStep, Ipp32fc* dst, size_t dstStep, const IppiDFTSpec_C_32fc* pDFTSpec, Ipp8u* pBuffer) const 1734 { 1735 return ippiDFT_CToC_32fc_C1R ? CV_INSTRUMENT_FUN_IPP(ippiDFT_CToC_32fc_C1R, src, static_cast<int>(srcStep), dst, static_cast<int>(dstStep), pDFTSpec, pBuffer) >= 0 : false; 1736 } 1737 private: 1738 ippiDFT_C_Func ippiDFT_CToC_32fc_C1R; 1739 }; 1740 1741 struct IPPDFT_R_Functor 1742 { 1743 IPPDFT_R_Functor(ippiDFT_R_Func _func) : ippiDFT_PackToR_32f_C1R(_func){} 1744 1745 bool operator()(const Ipp32f* src, size_t srcStep, Ipp32f* dst, size_t dstStep, const IppiDFTSpec_R_32f* pDFTSpec, Ipp8u* pBuffer) const 1746 { 1747 return ippiDFT_PackToR_32f_C1R ? CV_INSTRUMENT_FUN_IPP(ippiDFT_PackToR_32f_C1R, src, static_cast<int>(srcStep), dst, static_cast<int>(dstStep), pDFTSpec, pBuffer) >= 0 : false; 1748 } 1749 private: 1750 ippiDFT_R_Func ippiDFT_PackToR_32f_C1R; 1751 }; 1752 1753 static bool ippi_DFT_C_32F(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, bool inv, int norm_flag) 1754 { 1755 CV_INSTRUMENT_REGION_IPP(); 1756 1757 IppStatus status; 1758 Ipp8u* pBuffer = 0; 1759 Ipp8u* pMemInit= 0; 1760 int sizeBuffer=0; 1761 int sizeSpec=0; 1762 int sizeInit=0; 1763 1764 IppiSize srcRoiSize = {width, height}; 1765 1766 status = ippiDFTGetSize_C_32fc(srcRoiSize, norm_flag, ippAlgHintNone, &sizeSpec, &sizeInit, &sizeBuffer ); 1767 if ( status < 0 ) 1768 return false; 1769 1770 IppiDFTSpec_C_32fc* pDFTSpec = (IppiDFTSpec_C_32fc*)CV_IPP_MALLOC( sizeSpec ); 1771 1772 if ( sizeInit > 0 ) 1773 pMemInit = (Ipp8u*)CV_IPP_MALLOC( sizeInit ); 1774 1775 if ( sizeBuffer > 0 ) 1776 pBuffer = (Ipp8u*)CV_IPP_MALLOC( sizeBuffer ); 1777 1778 status = ippiDFTInit_C_32fc( srcRoiSize, norm_flag, ippAlgHintNone, pDFTSpec, pMemInit ); 1779 1780 if ( sizeInit > 0 ) 1781 ippFree( pMemInit ); 1782 1783 if ( status < 0 ) 1784 { 1785 ippFree( pDFTSpec ); 1786 if ( sizeBuffer > 0 ) 1787 ippFree( pBuffer ); 1788 return false; 1789 } 1790 1791 if (!inv) 1792 status = CV_INSTRUMENT_FUN_IPP(ippiDFTFwd_CToC_32fc_C1R, (Ipp32fc*)src, static_cast<int>(src_step), (Ipp32fc*)dst, static_cast<int>(dst_step), pDFTSpec, pBuffer); 1793 else 1794 status = CV_INSTRUMENT_FUN_IPP(ippiDFTInv_CToC_32fc_C1R, (Ipp32fc*)src, static_cast<int>(src_step), (Ipp32fc*)dst, static_cast<int>(dst_step), pDFTSpec, pBuffer); 1795 1796 if ( sizeBuffer > 0 ) 1797 ippFree( pBuffer ); 1798 1799 ippFree( pDFTSpec ); 1800 1801 if(status >= 0) 1802 { 1803 CV_IMPL_ADD(CV_IMPL_IPP); 1804 return true; 1805 } 1806 return false; 1807 } 1808 1809 static bool ippi_DFT_R_32F(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, bool inv, int norm_flag) 1810 { 1811 CV_INSTRUMENT_REGION_IPP(); 1812 1813 IppStatus status; 1814 Ipp8u* pBuffer = 0; 1815 Ipp8u* pMemInit= 0; 1816 int sizeBuffer=0; 1817 int sizeSpec=0; 1818 int sizeInit=0; 1819 1820 IppiSize srcRoiSize = {width, height}; 1821 1822 status = ippiDFTGetSize_R_32f(srcRoiSize, norm_flag, ippAlgHintNone, &sizeSpec, &sizeInit, &sizeBuffer ); 1823 if ( status < 0 ) 1824 return false; 1825 1826 IppiDFTSpec_R_32f* pDFTSpec = (IppiDFTSpec_R_32f*)CV_IPP_MALLOC( sizeSpec ); 1827 1828 if ( sizeInit > 0 ) 1829 pMemInit = (Ipp8u*)CV_IPP_MALLOC( sizeInit ); 1830 1831 if ( sizeBuffer > 0 ) 1832 pBuffer = (Ipp8u*)CV_IPP_MALLOC( sizeBuffer ); 1833 1834 status = ippiDFTInit_R_32f( srcRoiSize, norm_flag, ippAlgHintNone, pDFTSpec, pMemInit ); 1835 1836 if ( sizeInit > 0 ) 1837 ippFree( pMemInit ); 1838 1839 if ( status < 0 ) 1840 { 1841 ippFree( pDFTSpec ); 1842 if ( sizeBuffer > 0 ) 1843 ippFree( pBuffer ); 1844 return false; 1845 } 1846 1847 if (!inv) 1848 status = CV_INSTRUMENT_FUN_IPP(ippiDFTFwd_RToPack_32f_C1R, (float*)src, static_cast<int>(src_step), (float*)dst, static_cast<int>(dst_step), pDFTSpec, pBuffer); 1849 else 1850 status = CV_INSTRUMENT_FUN_IPP(ippiDFTInv_PackToR_32f_C1R, (float*)src, static_cast<int>(src_step), (float*)dst, static_cast<int>(dst_step), pDFTSpec, pBuffer); 1851 1852 if ( sizeBuffer > 0 ) 1853 ippFree( pBuffer ); 1854 1855 ippFree( pDFTSpec ); 1856 1857 if(status >= 0) 1858 { 1859 CV_IMPL_ADD(CV_IMPL_IPP); 1860 return true; 1861 } 1862 return false; 1863 } 1864 1865 #endif 1866 } 1867 1868 #ifdef HAVE_OPENCL 1869 1870 namespace cv 1871 { 1872 1873 enum FftType 1874 { 1875 R2R = 0, // real to CCS in case forward transform, CCS to real otherwise 1876 C2R = 1, // complex to real in case inverse transform 1877 R2C = 2, // real to complex in case forward transform 1878 C2C = 3 // complex to complex 1879 }; 1880 1881 struct OCL_FftPlan 1882 { 1883 private: 1884 UMat twiddles; 1885 String buildOptions; 1886 int thread_count; 1887 int dft_size; 1888 int dft_depth; 1889 bool status; 1890 1891 public: 1892 OCL_FftPlan(int _size, int _depth) : dft_size(_size), dft_depth(_depth), status(true) 1893 { 1894 CV_Assert( dft_depth == CV_32F || dft_depth == CV_64F ); 1895 1896 int min_radix; 1897 std::vector<int> radixes, blocks; 1898 ocl_getRadixes(dft_size, radixes, blocks, min_radix); 1899 thread_count = dft_size / min_radix; 1900 1901 if (thread_count > (int) ocl::Device::getDefault().maxWorkGroupSize()) 1902 { 1903 status = false; 1904 return; 1905 } 1906 1907 // generate string with radix calls 1908 String radix_processing; 1909 int n = 1, twiddle_size = 0; 1910 for (size_t i=0; i<radixes.size(); i++) 1911 { 1912 int radix = radixes[i], block = blocks[i]; 1913 if (block > 1) 1914 radix_processing += format("fft_radix%d_B%d(smem,twiddles+%d,ind,%d,%d);", radix, block, twiddle_size, n, dft_size/radix); 1915 else 1916 radix_processing += format("fft_radix%d(smem,twiddles+%d,ind,%d,%d);", radix, twiddle_size, n, dft_size/radix); 1917 twiddle_size += (radix-1)*n; 1918 n *= radix; 1919 } 1920 1921 twiddles.create(1, twiddle_size, CV_MAKE_TYPE(dft_depth, 2)); 1922 if (dft_depth == CV_32F) 1923 fillRadixTable<float>(twiddles, radixes); 1924 else 1925 fillRadixTable<double>(twiddles, radixes); 1926 1927 buildOptions = format("-D LOCAL_SIZE=%d -D kercn=%d -D FT=%s -D CT=%s%s -D RADIX_PROCESS=%s", 1928 dft_size, min_radix, ocl::typeToStr(dft_depth), ocl::typeToStr(CV_MAKE_TYPE(dft_depth, 2)), 1929 dft_depth == CV_64F ? " -D DOUBLE_SUPPORT" : "", radix_processing.c_str()); 1930 } 1931 1932 bool enqueueTransform(InputArray _src, OutputArray _dst, int num_dfts, int flags, int fftType, bool rows = true) const 1933 { 1934 if (!status) 1935 return false; 1936 1937 UMat src = _src.getUMat(); 1938 UMat dst = _dst.getUMat(); 1939 1940 size_t globalsize[2]; 1941 size_t localsize[2]; 1942 String kernel_name; 1943 1944 bool is1d = (flags & DFT_ROWS) != 0 || num_dfts == 1; 1945 bool inv = (flags & DFT_INVERSE) != 0; 1946 String options = buildOptions; 1947 1948 if (rows) 1949 { 1950 globalsize[0] = thread_count; globalsize[1] = src.rows; 1951 localsize[0] = thread_count; localsize[1] = 1; 1952 kernel_name = !inv ? "fft_multi_radix_rows" : "ifft_multi_radix_rows"; 1953 if ((is1d || inv) && (flags & DFT_SCALE)) 1954 options += " -D DFT_SCALE"; 1955 } 1956 else 1957 { 1958 globalsize[0] = num_dfts; globalsize[1] = thread_count; 1959 localsize[0] = 1; localsize[1] = thread_count; 1960 kernel_name = !inv ? "fft_multi_radix_cols" : "ifft_multi_radix_cols"; 1961 if (flags & DFT_SCALE) 1962 options += " -D DFT_SCALE"; 1963 } 1964 1965 options += src.channels() == 1 ? " -D REAL_INPUT" : " -D COMPLEX_INPUT"; 1966 options += dst.channels() == 1 ? " -D REAL_OUTPUT" : " -D COMPLEX_OUTPUT"; 1967 options += is1d ? " -D IS_1D" : ""; 1968 1969 if (!inv) 1970 { 1971 if ((is1d && src.channels() == 1) || (rows && (fftType == R2R))) 1972 options += " -D NO_CONJUGATE"; 1973 } 1974 else 1975 { 1976 if (rows && (fftType == C2R || fftType == R2R)) 1977 options += " -D NO_CONJUGATE"; 1978 if (dst.cols % 2 == 0) 1979 options += " -D EVEN"; 1980 } 1981 1982 ocl::Kernel k(kernel_name.c_str(), ocl::core::fft_oclsrc, options); 1983 if (k.empty()) 1984 return false; 1985 1986 k.args(ocl::KernelArg::ReadOnly(src), ocl::KernelArg::WriteOnly(dst), ocl::KernelArg::ReadOnlyNoSize(twiddles), thread_count, num_dfts); 1987 return k.run(2, globalsize, localsize, false); 1988 } 1989 1990 private: 1991 static void ocl_getRadixes(int cols, std::vector<int>& radixes, std::vector<int>& blocks, int& min_radix) 1992 { 1993 int factors[34]; 1994 int nf = DFTFactorize(cols, factors); 1995 1996 int n = 1; 1997 int factor_index = 0; 1998 min_radix = INT_MAX; 1999 2000 // 2^n transforms 2001 if ((factors[factor_index] & 1) == 0) 2002 { 2003 for( ; n < factors[factor_index];) 2004 { 2005 int radix = 2, block = 1; 2006 if (8*n <= factors[0]) 2007 radix = 8; 2008 else if (4*n <= factors[0]) 2009 { 2010 radix = 4; 2011 if (cols % 12 == 0) 2012 block = 3; 2013 else if (cols % 8 == 0) 2014 block = 2; 2015 } 2016 else 2017 { 2018 if (cols % 10 == 0) 2019 block = 5; 2020 else if (cols % 8 == 0) 2021 block = 4; 2022 else if (cols % 6 == 0) 2023 block = 3; 2024 else if (cols % 4 == 0) 2025 block = 2; 2026 } 2027 2028 radixes.push_back(radix); 2029 blocks.push_back(block); 2030 min_radix = min(min_radix, block*radix); 2031 n *= radix; 2032 } 2033 factor_index++; 2034 } 2035 2036 // all the other transforms 2037 for( ; factor_index < nf; factor_index++) 2038 { 2039 int radix = factors[factor_index], block = 1; 2040 if (radix == 3) 2041 { 2042 if (cols % 12 == 0) 2043 block = 4; 2044 else if (cols % 9 == 0) 2045 block = 3; 2046 else if (cols % 6 == 0) 2047 block = 2; 2048 } 2049 else if (radix == 5) 2050 { 2051 if (cols % 10 == 0) 2052 block = 2; 2053 } 2054 radixes.push_back(radix); 2055 blocks.push_back(block); 2056 min_radix = min(min_radix, block*radix); 2057 } 2058 } 2059 2060 template <typename T> 2061 static void fillRadixTable(UMat twiddles, const std::vector<int>& radixes) 2062 { 2063 Mat tw = twiddles.getMat(ACCESS_WRITE); 2064 T* ptr = tw.ptr<T>(); 2065 int ptr_index = 0; 2066 2067 int n = 1; 2068 for (size_t i=0; i<radixes.size(); i++) 2069 { 2070 int radix = radixes[i]; 2071 n *= radix; 2072 2073 for (int j=1; j<radix; j++) 2074 { 2075 double theta = -CV_2PI*j/n; 2076 2077 for (int k=0; k<(n/radix); k++) 2078 { 2079 ptr[ptr_index++] = (T) cos(k*theta); 2080 ptr[ptr_index++] = (T) sin(k*theta); 2081 } 2082 } 2083 } 2084 } 2085 }; 2086 2087 class OCL_FftPlanCache 2088 { 2089 public: 2090 static OCL_FftPlanCache & getInstance() 2091 { 2092 CV_SINGLETON_LAZY_INIT_REF(OCL_FftPlanCache, new OCL_FftPlanCache()) 2093 } 2094 2095 Ptr<OCL_FftPlan> getFftPlan(int dft_size, int depth) 2096 { 2097 int key = (dft_size << 16) | (depth & 0xFFFF); 2098 std::map<int, Ptr<OCL_FftPlan> >::iterator f = planStorage.find(key); 2099 if (f != planStorage.end()) 2100 { 2101 return f->second; 2102 } 2103 else 2104 { 2105 Ptr<OCL_FftPlan> newPlan = Ptr<OCL_FftPlan>(new OCL_FftPlan(dft_size, depth)); 2106 planStorage[key] = newPlan; 2107 return newPlan; 2108 } 2109 } 2110 2111 ~OCL_FftPlanCache() 2112 { 2113 planStorage.clear(); 2114 } 2115 2116 protected: 2117 OCL_FftPlanCache() : 2118 planStorage() 2119 { 2120 } 2121 std::map<int, Ptr<OCL_FftPlan> > planStorage; 2122 }; 2123 2124 static bool ocl_dft_rows(InputArray _src, OutputArray _dst, int nonzero_rows, int flags, int fftType) 2125 { 2126 int type = _src.type(), depth = CV_MAT_DEPTH(type); 2127 Ptr<OCL_FftPlan> plan = OCL_FftPlanCache::getInstance().getFftPlan(_src.cols(), depth); 2128 return plan->enqueueTransform(_src, _dst, nonzero_rows, flags, fftType, true); 2129 } 2130 2131 static bool ocl_dft_cols(InputArray _src, OutputArray _dst, int nonzero_cols, int flags, int fftType) 2132 { 2133 int type = _src.type(), depth = CV_MAT_DEPTH(type); 2134 Ptr<OCL_FftPlan> plan = OCL_FftPlanCache::getInstance().getFftPlan(_src.rows(), depth); 2135 return plan->enqueueTransform(_src, _dst, nonzero_cols, flags, fftType, false); 2136 } 2137 2138 inline FftType determineFFTType(bool real_input, bool complex_input, bool real_output, bool complex_output, bool inv) 2139 { 2140 // output format is not specified 2141 if (!real_output && !complex_output) 2142 complex_output = true; 2143 2144 // input or output format is ambiguous 2145 if (real_input == complex_input || real_output == complex_output) 2146 CV_Error(Error::StsBadArg, "Invalid FFT input or output format"); 2147 2148 FftType result = real_input ? (real_output ? R2R : R2C) : (real_output ? C2R : C2C); 2149 2150 // Forward Complex to CCS not supported 2151 if (result == C2R && !inv) 2152 result = C2C; 2153 2154 // Inverse CCS to Complex not supported 2155 if (result == R2C && inv) 2156 result = R2R; 2157 2158 return result; 2159 } 2160 2161 static bool ocl_dft(InputArray _src, OutputArray _dst, int flags, int nonzero_rows) 2162 { 2163 int type = _src.type(), cn = CV_MAT_CN(type), depth = CV_MAT_DEPTH(type); 2164 Size ssize = _src.size(); 2165 bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0; 2166 2167 if (!(cn == 1 || cn == 2) 2168 || !(depth == CV_32F || (depth == CV_64F && doubleSupport)) 2169 || ((flags & DFT_REAL_OUTPUT) && (flags & DFT_COMPLEX_OUTPUT))) 2170 return false; 2171 2172 // if is not a multiplication of prime numbers { 2, 3, 5 } 2173 if (ssize.area() != getOptimalDFTSize(ssize.area())) 2174 return false; 2175 2176 UMat src = _src.getUMat(); 2177 bool inv = (flags & DFT_INVERSE) != 0 ? 1 : 0; 2178 2179 if( nonzero_rows <= 0 || nonzero_rows > _src.rows() ) 2180 nonzero_rows = _src.rows(); 2181 bool is1d = (flags & DFT_ROWS) != 0 || nonzero_rows == 1; 2182 2183 FftType fftType = determineFFTType(cn == 1, cn == 2, 2184 (flags & DFT_REAL_OUTPUT) != 0, (flags & DFT_COMPLEX_OUTPUT) != 0, inv); 2185 2186 UMat output; 2187 if (fftType == C2C || fftType == R2C) 2188 { 2189 // complex output 2190 _dst.create(src.size(), CV_MAKETYPE(depth, 2)); 2191 output = _dst.getUMat(); 2192 } 2193 else 2194 { 2195 // real output 2196 if (is1d) 2197 { 2198 _dst.create(src.size(), CV_MAKETYPE(depth, 1)); 2199 output = _dst.getUMat(); 2200 } 2201 else 2202 { 2203 _dst.create(src.size(), CV_MAKETYPE(depth, 1)); 2204 output.create(src.size(), CV_MAKETYPE(depth, 2)); 2205 } 2206 } 2207 2208 bool result = false; 2209 if (!inv) 2210 { 2211 int nonzero_cols = fftType == R2R ? output.cols/2 + 1 : output.cols; 2212 result = ocl_dft_rows(src, output, nonzero_rows, flags, fftType); 2213 if (!is1d) 2214 result = result && ocl_dft_cols(output, _dst, nonzero_cols, flags, fftType); 2215 } 2216 else 2217 { 2218 if (fftType == C2C) 2219 { 2220 // complex output 2221 result = ocl_dft_rows(src, output, nonzero_rows, flags, fftType); 2222 if (!is1d) 2223 result = result && ocl_dft_cols(output, output, output.cols, flags, fftType); 2224 } 2225 else 2226 { 2227 if (is1d) 2228 { 2229 result = ocl_dft_rows(src, output, nonzero_rows, flags, fftType); 2230 } 2231 else 2232 { 2233 int nonzero_cols = src.cols/2 + 1; 2234 result = ocl_dft_cols(src, output, nonzero_cols, flags, fftType); 2235 result = result && ocl_dft_rows(output, _dst, nonzero_rows, flags, fftType); 2236 } 2237 } 2238 } 2239 return result; 2240 } 2241 2242 } // namespace cv; 2243 2244 #endif 2245 2246 #ifdef HAVE_CLAMDFFT 2247 2248 namespace cv { 2249 2250 #define CLAMDDFT_Assert(func) \ 2251 { \ 2252 clAmdFftStatus s = (func); \ 2253 CV_Assert(s == CLFFT_SUCCESS); \ 2254 } 2255 2256 class PlanCache 2257 { 2258 struct FftPlan 2259 { 2260 FftPlan(const Size & _dft_size, int _src_step, int _dst_step, bool _doubleFP, bool _inplace, int _flags, FftType _fftType) : 2261 dft_size(_dft_size), src_step(_src_step), dst_step(_dst_step), 2262 doubleFP(_doubleFP), inplace(_inplace), flags(_flags), fftType(_fftType), 2263 context((cl_context)ocl::Context::getDefault().ptr()), plHandle(0) 2264 { 2265 bool dft_inverse = (flags & DFT_INVERSE) != 0; 2266 bool dft_scale = (flags & DFT_SCALE) != 0; 2267 bool dft_rows = (flags & DFT_ROWS) != 0; 2268 2269 clAmdFftLayout inLayout = CLFFT_REAL, outLayout = CLFFT_REAL; 2270 clAmdFftDim dim = dft_size.height == 1 || dft_rows ? CLFFT_1D : CLFFT_2D; 2271 2272 size_t batchSize = dft_rows ? dft_size.height : 1; 2273 size_t clLengthsIn[3] = { (size_t)dft_size.width, dft_rows ? 1 : (size_t)dft_size.height, 1 }; 2274 size_t clStridesIn[3] = { 1, 1, 1 }; 2275 size_t clStridesOut[3] = { 1, 1, 1 }; 2276 int elemSize = doubleFP ? sizeof(double) : sizeof(float); 2277 2278 switch (fftType) 2279 { 2280 case C2C: 2281 inLayout = CLFFT_COMPLEX_INTERLEAVED; 2282 outLayout = CLFFT_COMPLEX_INTERLEAVED; 2283 clStridesIn[1] = src_step / (elemSize << 1); 2284 clStridesOut[1] = dst_step / (elemSize << 1); 2285 break; 2286 case R2C: 2287 inLayout = CLFFT_REAL; 2288 outLayout = CLFFT_HERMITIAN_INTERLEAVED; 2289 clStridesIn[1] = src_step / elemSize; 2290 clStridesOut[1] = dst_step / (elemSize << 1); 2291 break; 2292 case C2R: 2293 inLayout = CLFFT_HERMITIAN_INTERLEAVED; 2294 outLayout = CLFFT_REAL; 2295 clStridesIn[1] = src_step / (elemSize << 1); 2296 clStridesOut[1] = dst_step / elemSize; 2297 break; 2298 case R2R: 2299 default: 2300 CV_Error(Error::StsNotImplemented, "AMD Fft does not support this type"); 2301 break; 2302 } 2303 2304 clStridesIn[2] = dft_rows ? clStridesIn[1] : dft_size.width * clStridesIn[1]; 2305 clStridesOut[2] = dft_rows ? clStridesOut[1] : dft_size.width * clStridesOut[1]; 2306 2307 CLAMDDFT_Assert(clAmdFftCreateDefaultPlan(&plHandle, (cl_context)ocl::Context::getDefault().ptr(), dim, clLengthsIn)) 2308 2309 // setting plan properties 2310 CLAMDDFT_Assert(clAmdFftSetPlanPrecision(plHandle, doubleFP ? CLFFT_DOUBLE : CLFFT_SINGLE)); 2311 CLAMDDFT_Assert(clAmdFftSetResultLocation(plHandle, inplace ? CLFFT_INPLACE : CLFFT_OUTOFPLACE)) 2312 CLAMDDFT_Assert(clAmdFftSetLayout(plHandle, inLayout, outLayout)) 2313 CLAMDDFT_Assert(clAmdFftSetPlanBatchSize(plHandle, batchSize)) 2314 CLAMDDFT_Assert(clAmdFftSetPlanInStride(plHandle, dim, clStridesIn)) 2315 CLAMDDFT_Assert(clAmdFftSetPlanOutStride(plHandle, dim, clStridesOut)) 2316 CLAMDDFT_Assert(clAmdFftSetPlanDistance(plHandle, clStridesIn[dim], clStridesOut[dim])) 2317 2318 float scale = dft_scale ? 1.0f / (dft_rows ? dft_size.width : dft_size.area()) : 1.0f; 2319 CLAMDDFT_Assert(clAmdFftSetPlanScale(plHandle, dft_inverse ? CLFFT_BACKWARD : CLFFT_FORWARD, scale)) 2320 2321 // ready to bake 2322 cl_command_queue queue = (cl_command_queue)ocl::Queue::getDefault().ptr(); 2323 CLAMDDFT_Assert(clAmdFftBakePlan(plHandle, 1, &queue, NULL, NULL)) 2324 } 2325 2326 ~FftPlan() 2327 { 2328 // clAmdFftDestroyPlan(&plHandle); 2329 } 2330 2331 friend class PlanCache; 2332 2333 private: 2334 Size dft_size; 2335 int src_step, dst_step; 2336 bool doubleFP; 2337 bool inplace; 2338 int flags; 2339 FftType fftType; 2340 2341 cl_context context; 2342 clAmdFftPlanHandle plHandle; 2343 }; 2344 2345 public: 2346 static PlanCache & getInstance() 2347 { 2348 CV_SINGLETON_LAZY_INIT_REF(PlanCache, new PlanCache()) 2349 } 2350 2351 clAmdFftPlanHandle getPlanHandle(const Size & dft_size, int src_step, int dst_step, bool doubleFP, 2352 bool inplace, int flags, FftType fftType) 2353 { 2354 cl_context currentContext = (cl_context)ocl::Context::getDefault().ptr(); 2355 2356 for (size_t i = 0, size = planStorage.size(); i < size; ++i) 2357 { 2358 const FftPlan * const plan = planStorage[i]; 2359 2360 if (plan->dft_size == dft_size && 2361 plan->flags == flags && 2362 plan->src_step == src_step && 2363 plan->dst_step == dst_step && 2364 plan->doubleFP == doubleFP && 2365 plan->fftType == fftType && 2366 plan->inplace == inplace) 2367 { 2368 if (plan->context != currentContext) 2369 { 2370 planStorage.erase(planStorage.begin() + i); 2371 break; 2372 } 2373 2374 return plan->plHandle; 2375 } 2376 } 2377 2378 // no baked plan is found, so let's create a new one 2379 Ptr<FftPlan> newPlan = Ptr<FftPlan>(new FftPlan(dft_size, src_step, dst_step, doubleFP, inplace, flags, fftType)); 2380 planStorage.push_back(newPlan); 2381 2382 return newPlan->plHandle; 2383 } 2384 2385 ~PlanCache() 2386 { 2387 planStorage.clear(); 2388 } 2389 2390 protected: 2391 PlanCache() : 2392 planStorage() 2393 { 2394 } 2395 2396 std::vector<Ptr<FftPlan> > planStorage; 2397 }; 2398 2399 extern "C" { 2400 2401 static void CL_CALLBACK oclCleanupCallback(cl_event e, cl_int, void *p) 2402 { 2403 UMatData * u = (UMatData *)p; 2404 2405 if( u && CV_XADD(&u->urefcount, -1) == 1 ) 2406 u->currAllocator->deallocate(u); 2407 u = 0; 2408 2409 clReleaseEvent(e), e = 0; 2410 } 2411 2412 } 2413 2414 static bool ocl_dft_amdfft(InputArray _src, OutputArray _dst, int flags) 2415 { 2416 int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); 2417 Size ssize = _src.size(); 2418 2419 bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0; 2420 if ( (!doubleSupport && depth == CV_64F) || 2421 !(type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2) || 2422 _src.offset() != 0) 2423 return false; 2424 2425 // if is not a multiplication of prime numbers { 2, 3, 5 } 2426 if (ssize.area() != getOptimalDFTSize(ssize.area())) 2427 return false; 2428 2429 int dst_complex_input = cn == 2 ? 1 : 0; 2430 bool dft_inverse = (flags & DFT_INVERSE) != 0 ? 1 : 0; 2431 int dft_complex_output = (flags & DFT_COMPLEX_OUTPUT) != 0; 2432 bool dft_real_output = (flags & DFT_REAL_OUTPUT) != 0; 2433 2434 CV_Assert(dft_complex_output + dft_real_output < 2); 2435 FftType fftType = (FftType)(dst_complex_input << 0 | dft_complex_output << 1); 2436 2437 switch (fftType) 2438 { 2439 case C2C: 2440 _dst.create(ssize.height, ssize.width, CV_MAKE_TYPE(depth, 2)); 2441 break; 2442 case R2C: // TODO implement it if possible 2443 case C2R: // TODO implement it if possible 2444 case R2R: // AMD Fft does not support this type 2445 default: 2446 return false; 2447 } 2448 2449 UMat src = _src.getUMat(), dst = _dst.getUMat(); 2450 bool inplace = src.u == dst.u; 2451 2452 clAmdFftPlanHandle plHandle = PlanCache::getInstance(). 2453 getPlanHandle(ssize, (int)src.step, (int)dst.step, 2454 depth == CV_64F, inplace, flags, fftType); 2455 2456 // get the bufferSize 2457 size_t bufferSize = 0; 2458 CLAMDDFT_Assert(clAmdFftGetTmpBufSize(plHandle, &bufferSize)) 2459 UMat tmpBuffer(1, (int)bufferSize, CV_8UC1); 2460 2461 cl_mem srcarg = (cl_mem)src.handle(ACCESS_READ); 2462 cl_mem dstarg = (cl_mem)dst.handle(ACCESS_RW); 2463 2464 cl_command_queue queue = (cl_command_queue)ocl::Queue::getDefault().ptr(); 2465 cl_event e = 0; 2466 2467 CLAMDDFT_Assert(clAmdFftEnqueueTransform(plHandle, dft_inverse ? CLFFT_BACKWARD : CLFFT_FORWARD, 2468 1, &queue, 0, NULL, &e, 2469 &srcarg, &dstarg, (cl_mem)tmpBuffer.handle(ACCESS_RW))) 2470 2471 tmpBuffer.addref(); 2472 clSetEventCallback(e, CL_COMPLETE, oclCleanupCallback, tmpBuffer.u); 2473 return true; 2474 } 2475 2476 #undef DFT_ASSERT 2477 2478 } 2479 2480 #endif // HAVE_CLAMDFFT 2481 2482 namespace cv 2483 { 2484 2485 template <typename T> 2486 static void complementComplex(T * ptr, size_t step, int n, int len, int dft_dims) 2487 { 2488 T* p0 = (T*)ptr; 2489 size_t dstep = step/sizeof(p0[0]); 2490 for(int i = 0; i < len; i++ ) 2491 { 2492 T* p = p0 + dstep*i; 2493 T* q = dft_dims == 1 || i == 0 || i*2 == len ? p : p0 + dstep*(len-i); 2494 2495 for( int j = 1; j < (n+1)/2; j++ ) 2496 { 2497 p[(n-j)*2] = q[j*2]; 2498 p[(n-j)*2+1] = -q[j*2+1]; 2499 } 2500 } 2501 } 2502 2503 static void complementComplexOutput(int depth, uchar * ptr, size_t step, int count, int len, int dft_dims) 2504 { 2505 if( depth == CV_32F ) 2506 complementComplex((float*)ptr, step, count, len, dft_dims); 2507 else 2508 complementComplex((double*)ptr, step, count, len, dft_dims); 2509 } 2510 2511 enum DftMode { 2512 InvalidDft = 0, 2513 FwdRealToCCS, 2514 FwdRealToComplex, 2515 FwdComplexToComplex, 2516 InvCCSToReal, 2517 InvComplexToReal, 2518 InvComplexToComplex, 2519 }; 2520 2521 enum DftDims { 2522 InvalidDim = 0, 2523 OneDim, 2524 OneDimColWise, 2525 TwoDims 2526 }; 2527 2528 inline const char * modeName(DftMode m) 2529 { 2530 switch (m) 2531 { 2532 case InvalidDft: return "InvalidDft"; 2533 case FwdRealToCCS: return "FwdRealToCCS"; 2534 case FwdRealToComplex: return "FwdRealToComplex"; 2535 case FwdComplexToComplex: return "FwdComplexToComplex"; 2536 case InvCCSToReal: return "InvCCSToReal"; 2537 case InvComplexToReal: return "InvComplexToReal"; 2538 case InvComplexToComplex: return "InvComplexToComplex"; 2539 } 2540 return 0; 2541 } 2542 2543 inline const char * dimsName(DftDims d) 2544 { 2545 switch (d) 2546 { 2547 case InvalidDim: return "InvalidDim"; 2548 case OneDim: return "OneDim"; 2549 case OneDimColWise: return "OneDimColWise"; 2550 case TwoDims: return "TwoDims"; 2551 }; 2552 return 0; 2553 } 2554 2555 template <typename T> 2556 inline bool isInv(T mode) 2557 { 2558 switch ((DftMode)mode) 2559 { 2560 case InvCCSToReal: 2561 case InvComplexToReal: 2562 case InvComplexToComplex: return true; 2563 default: return false; 2564 } 2565 } 2566 2567 inline DftMode determineMode(bool inv, int cn1, int cn2) 2568 { 2569 if (!inv) 2570 { 2571 if (cn1 == 1 && cn2 == 1) 2572 return FwdRealToCCS; 2573 else if (cn1 == 1 && cn2 == 2) 2574 return FwdRealToComplex; 2575 else if (cn1 == 2 && cn2 == 2) 2576 return FwdComplexToComplex; 2577 } 2578 else 2579 { 2580 if (cn1 == 1 && cn2 == 1) 2581 return InvCCSToReal; 2582 else if (cn1 == 2 && cn2 == 1) 2583 return InvComplexToReal; 2584 else if (cn1 == 2 && cn2 == 2) 2585 return InvComplexToComplex; 2586 } 2587 return InvalidDft; 2588 } 2589 2590 2591 inline DftDims determineDims(int rows, int cols, bool isRowWise, bool isContinuous) 2592 { 2593 // printf("%d x %d (%d, %d)\n", rows, cols, isRowWise, isContinuous); 2594 if (isRowWise) 2595 return OneDim; 2596 if (cols == 1 && rows > 1) // one-column-shaped input 2597 { 2598 if (isContinuous) 2599 return OneDim; 2600 else 2601 return OneDimColWise; 2602 } 2603 if (rows == 1) 2604 return OneDim; 2605 if (cols > 1 && rows > 1) 2606 return TwoDims; 2607 return InvalidDim; 2608 } 2609 2610 class OcvDftImpl CV_FINAL : public hal::DFT2D 2611 { 2612 protected: 2613 Ptr<hal::DFT1D> contextA; 2614 Ptr<hal::DFT1D> contextB; 2615 bool needBufferA; 2616 bool needBufferB; 2617 bool inv; 2618 int width; 2619 int height; 2620 DftMode mode; 2621 int elem_size; 2622 int complex_elem_size; 2623 int depth; 2624 bool real_transform; 2625 int nonzero_rows; 2626 bool isRowTransform; 2627 bool isScaled; 2628 std::vector<int> stages; 2629 bool useIpp; 2630 int src_channels; 2631 int dst_channels; 2632 2633 AutoBuffer<uchar> tmp_bufA; 2634 AutoBuffer<uchar> tmp_bufB; 2635 AutoBuffer<uchar> buf0; 2636 AutoBuffer<uchar> buf1; 2637 2638 public: 2639 OcvDftImpl() 2640 { 2641 needBufferA = false; 2642 needBufferB = false; 2643 inv = false; 2644 width = 0; 2645 height = 0; 2646 mode = InvalidDft; 2647 elem_size = 0; 2648 complex_elem_size = 0; 2649 depth = 0; 2650 real_transform = false; 2651 nonzero_rows = 0; 2652 isRowTransform = false; 2653 isScaled = false; 2654 useIpp = false; 2655 src_channels = 0; 2656 dst_channels = 0; 2657 } 2658 2659 void init(int _width, int _height, int _depth, int _src_channels, int _dst_channels, int flags, int _nonzero_rows) 2660 { 2661 bool isComplex = _src_channels != _dst_channels; 2662 nonzero_rows = _nonzero_rows; 2663 width = _width; 2664 height = _height; 2665 depth = _depth; 2666 src_channels = _src_channels; 2667 dst_channels = _dst_channels; 2668 bool isInverse = (flags & CV_HAL_DFT_INVERSE) != 0; 2669 bool isInplace = (flags & CV_HAL_DFT_IS_INPLACE) != 0; 2670 bool isContinuous = (flags & CV_HAL_DFT_IS_CONTINUOUS) != 0; 2671 mode = determineMode(isInverse, _src_channels, _dst_channels); 2672 inv = isInverse; 2673 isRowTransform = (flags & CV_HAL_DFT_ROWS) != 0; 2674 isScaled = (flags & CV_HAL_DFT_SCALE) != 0; 2675 needBufferA = false; 2676 needBufferB = false; 2677 real_transform = (mode != FwdComplexToComplex && mode != InvComplexToComplex); 2678 2679 elem_size = (depth == CV_32F) ? sizeof(float) : sizeof(double); 2680 complex_elem_size = elem_size * 2; 2681 if( !real_transform ) 2682 elem_size = complex_elem_size; 2683 2684 #if defined USE_IPP_DFT 2685 CV_IPP_CHECK() 2686 { 2687 if (nonzero_rows == 0 && depth == CV_32F && ((width * height)>(int)(1<<6))) 2688 { 2689 if (mode == FwdComplexToComplex || mode == InvComplexToComplex || mode == FwdRealToCCS || mode == InvCCSToReal) 2690 { 2691 useIpp = true; 2692 return; 2693 } 2694 } 2695 } 2696 #endif 2697 2698 DftDims dims = determineDims(height, width, isRowTransform, isContinuous); 2699 if (dims == TwoDims) 2700 { 2701 stages.resize(2); 2702 if (mode == InvCCSToReal || mode == InvComplexToReal) 2703 { 2704 stages[0] = 1; 2705 stages[1] = 0; 2706 } 2707 else 2708 { 2709 stages[0] = 0; 2710 stages[1] = 1; 2711 } 2712 } 2713 else 2714 { 2715 stages.resize(1); 2716 if (dims == OneDimColWise) 2717 stages[0] = 1; 2718 else 2719 stages[0] = 0; 2720 } 2721 2722 for(uint stageIndex = 0; stageIndex < stages.size(); ++stageIndex) 2723 { 2724 if (stageIndex == 1) 2725 { 2726 isInplace = true; 2727 isComplex = false; 2728 } 2729 2730 int stage = stages[stageIndex]; 2731 bool isLastStage = (stageIndex + 1 == stages.size()); 2732 2733 int len, count; 2734 2735 int f = 0; 2736 if (inv) 2737 f |= CV_HAL_DFT_INVERSE; 2738 if (isScaled) 2739 f |= CV_HAL_DFT_SCALE; 2740 if (isRowTransform) 2741 f |= CV_HAL_DFT_ROWS; 2742 if (isComplex) 2743 f |= CV_HAL_DFT_COMPLEX_OUTPUT; 2744 if (real_transform) 2745 f |= CV_HAL_DFT_REAL_OUTPUT; 2746 if (!isLastStage) 2747 f |= CV_HAL_DFT_TWO_STAGE; 2748 2749 if( stage == 0 ) // row-wise transform 2750 { 2751 if (width == 1 && !isRowTransform ) 2752 { 2753 len = height; 2754 count = width; 2755 } 2756 else 2757 { 2758 len = width; 2759 count = height; 2760 } 2761 needBufferA = isInplace; 2762 contextA = hal::DFT1D::create(len, count, depth, f, &needBufferA); 2763 if (needBufferA) 2764 tmp_bufA.allocate(len * complex_elem_size); 2765 } 2766 else 2767 { 2768 len = height; 2769 count = width; 2770 f |= CV_HAL_DFT_STAGE_COLS; 2771 needBufferB = isInplace; 2772 contextB = hal::DFT1D::create(len, count, depth, f, &needBufferB); 2773 if (needBufferB) 2774 tmp_bufB.allocate(len * complex_elem_size); 2775 2776 buf0.allocate(len * complex_elem_size); 2777 buf1.allocate(len * complex_elem_size); 2778 } 2779 } 2780 } 2781 2782 void apply(const uchar * src, size_t src_step, uchar * dst, size_t dst_step) CV_OVERRIDE 2783 { 2784 #if defined USE_IPP_DFT 2785 if (useIpp) 2786 { 2787 int ipp_norm_flag = !isScaled ? 8 : inv ? 2 : 1; 2788 if (!isRowTransform) 2789 { 2790 if (mode == FwdComplexToComplex || mode == InvComplexToComplex) 2791 { 2792 if (ippi_DFT_C_32F(src, src_step, dst, dst_step, width, height, inv, ipp_norm_flag)) 2793 { 2794 CV_IMPL_ADD(CV_IMPL_IPP); 2795 return; 2796 } 2797 setIppErrorStatus(); 2798 } 2799 else if (mode == FwdRealToCCS || mode == InvCCSToReal) 2800 { 2801 if (ippi_DFT_R_32F(src, src_step, dst, dst_step, width, height, inv, ipp_norm_flag)) 2802 { 2803 CV_IMPL_ADD(CV_IMPL_IPP); 2804 return; 2805 } 2806 setIppErrorStatus(); 2807 } 2808 } 2809 else 2810 { 2811 if (mode == FwdComplexToComplex || mode == InvComplexToComplex) 2812 { 2813 ippiDFT_C_Func ippiFunc = inv ? (ippiDFT_C_Func)ippiDFTInv_CToC_32fc_C1R : (ippiDFT_C_Func)ippiDFTFwd_CToC_32fc_C1R; 2814 if (Dft_C_IPPLoop(src, src_step, dst, dst_step, width, height, IPPDFT_C_Functor(ippiFunc),ipp_norm_flag)) 2815 { 2816 CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); 2817 return; 2818 } 2819 setIppErrorStatus(); 2820 } 2821 else if (mode == FwdRealToCCS || mode == InvCCSToReal) 2822 { 2823 ippiDFT_R_Func ippiFunc = inv ? (ippiDFT_R_Func)ippiDFTInv_PackToR_32f_C1R : (ippiDFT_R_Func)ippiDFTFwd_RToPack_32f_C1R; 2824 if (Dft_R_IPPLoop(src, src_step, dst, dst_step, width, height, IPPDFT_R_Functor(ippiFunc),ipp_norm_flag)) 2825 { 2826 CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); 2827 return; 2828 } 2829 setIppErrorStatus(); 2830 } 2831 } 2832 return; 2833 } 2834 #endif 2835 2836 for(uint stageIndex = 0; stageIndex < stages.size(); ++stageIndex) 2837 { 2838 int stage_src_channels = src_channels; 2839 int stage_dst_channels = dst_channels; 2840 2841 if (stageIndex == 1) 2842 { 2843 src = dst; 2844 src_step = dst_step; 2845 stage_src_channels = stage_dst_channels; 2846 } 2847 2848 int stage = stages[stageIndex]; 2849 bool isLastStage = (stageIndex + 1 == stages.size()); 2850 bool isComplex = stage_src_channels != stage_dst_channels; 2851 2852 if( stage == 0 ) 2853 rowDft(src, src_step, dst, dst_step, isComplex, isLastStage); 2854 else 2855 colDft(src, src_step, dst, dst_step, stage_src_channels, stage_dst_channels, isLastStage); 2856 } 2857 } 2858 2859 protected: 2860 2861 void rowDft(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, bool isComplex, bool isLastStage) 2862 { 2863 int len, count; 2864 if (width == 1 && !isRowTransform ) 2865 { 2866 len = height; 2867 count = width; 2868 } 2869 else 2870 { 2871 len = width; 2872 count = height; 2873 } 2874 int dptr_offset = 0; 2875 int dst_full_len = len*elem_size; 2876 2877 if( needBufferA ) 2878 { 2879 if (mode == FwdRealToCCS && (len & 1) && len > 1) 2880 dptr_offset = elem_size; 2881 } 2882 2883 if( !inv && isComplex ) 2884 dst_full_len += (len & 1) ? elem_size : complex_elem_size; 2885 2886 int nz = nonzero_rows; 2887 if( nz <= 0 || nz > count ) 2888 nz = count; 2889 2890 int i; 2891 for( i = 0; i < nz; i++ ) 2892 { 2893 const uchar* sptr = src_data + src_step * i; 2894 uchar* dptr0 = dst_data + dst_step * i; 2895 uchar* dptr = dptr0; 2896 2897 if( needBufferA ) 2898 dptr = tmp_bufA.data(); 2899 2900 contextA->apply(sptr, dptr); 2901 2902 if( needBufferA ) 2903 memcpy( dptr0, dptr + dptr_offset, dst_full_len ); 2904 } 2905 2906 for( ; i < count; i++ ) 2907 { 2908 uchar* dptr0 = dst_data + dst_step * i; 2909 memset( dptr0, 0, dst_full_len ); 2910 } 2911 if(isLastStage && mode == FwdRealToComplex) 2912 complementComplexOutput(depth, dst_data, dst_step, len, nz, 1); 2913 } 2914 2915 void colDft(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int stage_src_channels, int stage_dst_channels, bool isLastStage) 2916 { 2917 int len = height; 2918 int count = width; 2919 int a = 0, b = count; 2920 uchar *dbuf0, *dbuf1; 2921 const uchar* sptr0 = src_data; 2922 uchar* dptr0 = dst_data; 2923 2924 dbuf0 = buf0.data(), dbuf1 = buf1.data(); 2925 2926 if( needBufferB ) 2927 { 2928 dbuf1 = tmp_bufB.data(); 2929 dbuf0 = buf1.data(); 2930 } 2931 2932 if( real_transform ) 2933 { 2934 int even; 2935 a = 1; 2936 even = (count & 1) == 0; 2937 b = (count+1)/2; 2938 if( !inv ) 2939 { 2940 memset( buf0.data(), 0, len*complex_elem_size ); 2941 CopyColumn( sptr0, src_step, buf0.data(), complex_elem_size, len, elem_size ); 2942 sptr0 += stage_dst_channels*elem_size; 2943 if( even ) 2944 { 2945 memset( buf1.data(), 0, len*complex_elem_size ); 2946 CopyColumn( sptr0 + (count-2)*elem_size, src_step, 2947 buf1.data(), complex_elem_size, len, elem_size ); 2948 } 2949 } 2950 else if( stage_src_channels == 1 ) 2951 { 2952 CopyColumn( sptr0, src_step, buf0.data(), elem_size, len, elem_size ); 2953 ExpandCCS( buf0.data(), len, elem_size ); 2954 if( even ) 2955 { 2956 CopyColumn( sptr0 + (count-1)*elem_size, src_step, 2957 buf1.data(), elem_size, len, elem_size ); 2958 ExpandCCS( buf1.data(), len, elem_size ); 2959 } 2960 sptr0 += elem_size; 2961 } 2962 else 2963 { 2964 CopyColumn( sptr0, src_step, buf0.data(), complex_elem_size, len, complex_elem_size ); 2965 if( even ) 2966 { 2967 CopyColumn( sptr0 + b*complex_elem_size, src_step, 2968 buf1.data(), complex_elem_size, len, complex_elem_size ); 2969 } 2970 sptr0 += complex_elem_size; 2971 } 2972 2973 if( even ) 2974 contextB->apply(buf1.data(), dbuf1); 2975 contextB->apply(buf0.data(), dbuf0); 2976 2977 if( stage_dst_channels == 1 ) 2978 { 2979 if( !inv ) 2980 { 2981 // copy the half of output vector to the first/last column. 2982 // before doing that, defgragment the vector 2983 memcpy( dbuf0 + elem_size, dbuf0, elem_size ); 2984 CopyColumn( dbuf0 + elem_size, elem_size, dptr0, 2985 dst_step, len, elem_size ); 2986 if( even ) 2987 { 2988 memcpy( dbuf1 + elem_size, dbuf1, elem_size ); 2989 CopyColumn( dbuf1 + elem_size, elem_size, 2990 dptr0 + (count-1)*elem_size, 2991 dst_step, len, elem_size ); 2992 } 2993 dptr0 += elem_size; 2994 } 2995 else 2996 { 2997 // copy the real part of the complex vector to the first/last column 2998 CopyColumn( dbuf0, complex_elem_size, dptr0, dst_step, len, elem_size ); 2999 if( even ) 3000 CopyColumn( dbuf1, complex_elem_size, dptr0 + (count-1)*elem_size, 3001 dst_step, len, elem_size ); 3002 dptr0 += elem_size; 3003 } 3004 } 3005 else 3006 { 3007 assert( !inv ); 3008 CopyColumn( dbuf0, complex_elem_size, dptr0, 3009 dst_step, len, complex_elem_size ); 3010 if( even ) 3011 CopyColumn( dbuf1, complex_elem_size, 3012 dptr0 + b*complex_elem_size, 3013 dst_step, len, complex_elem_size ); 3014 dptr0 += complex_elem_size; 3015 } 3016 } 3017 3018 for(int i = a; i < b; i += 2 ) 3019 { 3020 if( i+1 < b ) 3021 { 3022 CopyFrom2Columns( sptr0, src_step, buf0.data(), buf1.data(), len, complex_elem_size ); 3023 contextB->apply(buf1.data(), dbuf1); 3024 } 3025 else 3026 CopyColumn( sptr0, src_step, buf0.data(), complex_elem_size, len, complex_elem_size ); 3027 3028 contextB->apply(buf0.data(), dbuf0); 3029 3030 if( i+1 < b ) 3031 CopyTo2Columns( dbuf0, dbuf1, dptr0, dst_step, len, complex_elem_size ); 3032 else 3033 CopyColumn( dbuf0, complex_elem_size, dptr0, dst_step, len, complex_elem_size ); 3034 sptr0 += 2*complex_elem_size; 3035 dptr0 += 2*complex_elem_size; 3036 } 3037 if(isLastStage && mode == FwdRealToComplex) 3038 complementComplexOutput(depth, dst_data, dst_step, count, len, 2); 3039 } 3040 }; 3041 3042 class OcvDftBasicImpl CV_FINAL : public hal::DFT1D 3043 { 3044 public: 3045 OcvDftOptions opt; 3046 int _factors[34]; 3047 AutoBuffer<uchar> wave_buf; 3048 AutoBuffer<int> itab_buf; 3049 #ifdef USE_IPP_DFT 3050 AutoBuffer<uchar> ippbuf; 3051 AutoBuffer<uchar> ippworkbuf; 3052 #endif 3053 3054 public: 3055 OcvDftBasicImpl() 3056 { 3057 opt.factors = _factors; 3058 } 3059 void init(int len, int count, int depth, int flags, bool *needBuffer) 3060 { 3061 int prev_len = opt.n; 3062 3063 int stage = (flags & CV_HAL_DFT_STAGE_COLS) != 0 ? 1 : 0; 3064 int complex_elem_size = depth == CV_32F ? sizeof(Complex<float>) : sizeof(Complex<double>); 3065 opt.isInverse = (flags & CV_HAL_DFT_INVERSE) != 0; 3066 bool real_transform = (flags & CV_HAL_DFT_REAL_OUTPUT) != 0; 3067 opt.isComplex = (stage == 0) && (flags & CV_HAL_DFT_COMPLEX_OUTPUT) != 0; 3068 bool needAnotherStage = (flags & CV_HAL_DFT_TWO_STAGE) != 0; 3069 3070 opt.scale = 1; 3071 opt.tab_size = len; 3072 opt.n = len; 3073 3074 opt.useIpp = false; 3075 #ifdef USE_IPP_DFT 3076 opt.ipp_spec = 0; 3077 opt.ipp_work = 0; 3078 3079 if( CV_IPP_CHECK_COND && (opt.n*count >= 64) ) // use IPP DFT if available 3080 { 3081 int ipp_norm_flag = (flags & CV_HAL_DFT_SCALE) == 0 ? 8 : opt.isInverse ? 2 : 1; 3082 int specsize=0, initsize=0, worksize=0; 3083 IppDFTGetSizeFunc getSizeFunc = 0; 3084 IppDFTInitFunc initFunc = 0; 3085 3086 if( real_transform && stage == 0 ) 3087 { 3088 if( depth == CV_32F ) 3089 { 3090 getSizeFunc = ippsDFTGetSize_R_32f; 3091 initFunc = (IppDFTInitFunc)ippsDFTInit_R_32f; 3092 } 3093 else 3094 { 3095 getSizeFunc = ippsDFTGetSize_R_64f; 3096 initFunc = (IppDFTInitFunc)ippsDFTInit_R_64f; 3097 } 3098 } 3099 else 3100 { 3101 if( depth == CV_32F ) 3102 { 3103 getSizeFunc = ippsDFTGetSize_C_32fc; 3104 initFunc = (IppDFTInitFunc)ippsDFTInit_C_32fc; 3105 } 3106 else 3107 { 3108 getSizeFunc = ippsDFTGetSize_C_64fc; 3109 initFunc = (IppDFTInitFunc)ippsDFTInit_C_64fc; 3110 } 3111 } 3112 if( getSizeFunc(opt.n, ipp_norm_flag, ippAlgHintNone, &specsize, &initsize, &worksize) >= 0 ) 3113 { 3114 ippbuf.allocate(specsize + initsize + 64); 3115 opt.ipp_spec = alignPtr(&ippbuf[0], 32); 3116 ippworkbuf.allocate(worksize + 32); 3117 opt.ipp_work = alignPtr(&ippworkbuf[0], 32); 3118 uchar* initbuf = alignPtr((uchar*)opt.ipp_spec + specsize, 32); 3119 if( initFunc(opt.n, ipp_norm_flag, ippAlgHintNone, opt.ipp_spec, initbuf) >= 0 ) 3120 opt.useIpp = true; 3121 } 3122 else 3123 setIppErrorStatus(); 3124 } 3125 #endif 3126 3127 if (!opt.useIpp) 3128 { 3129 if (len != prev_len) 3130 { 3131 opt.nf = DFTFactorize( opt.n, opt.factors ); 3132 } 3133 bool inplace_transform = opt.factors[0] == opt.factors[opt.nf-1]; 3134 if (len != prev_len || (!inplace_transform && opt.isInverse && real_transform)) 3135 { 3136 wave_buf.allocate(opt.n*complex_elem_size); 3137 opt.wave = wave_buf.data(); 3138 itab_buf.allocate(opt.n); 3139 opt.itab = itab_buf.data(); 3140 DFTInit( opt.n, opt.nf, opt.factors, opt.itab, complex_elem_size, 3141 opt.wave, stage == 0 && opt.isInverse && real_transform ); 3142 } 3143 // otherwise reuse the tables calculated on the previous stage 3144 if (needBuffer) 3145 { 3146 if( (stage == 0 && ((*needBuffer && !inplace_transform) || (real_transform && (len & 1)))) || 3147 (stage == 1 && !inplace_transform) ) 3148 { 3149 *needBuffer = true; 3150 } 3151 } 3152 } 3153 else 3154 { 3155 if (needBuffer) 3156 { 3157 *needBuffer = false; 3158 } 3159 } 3160 3161 { 3162 static DFTFunc dft_tbl[6] = 3163 { 3164 (DFTFunc)DFT_32f, 3165 (DFTFunc)RealDFT_32f, 3166 (DFTFunc)CCSIDFT_32f, 3167 (DFTFunc)DFT_64f, 3168 (DFTFunc)RealDFT_64f, 3169 (DFTFunc)CCSIDFT_64f 3170 }; 3171 int idx = 0; 3172 if (stage == 0) 3173 { 3174 if (real_transform) 3175 { 3176 if (!opt.isInverse) 3177 idx = 1; 3178 else 3179 idx = 2; 3180 } 3181 } 3182 if (depth == CV_64F) 3183 idx += 3; 3184 3185 opt.dft_func = dft_tbl[idx]; 3186 } 3187 3188 if(!needAnotherStage && (flags & CV_HAL_DFT_SCALE) != 0) 3189 { 3190 int rowCount = count; 3191 if (stage == 0 && (flags & CV_HAL_DFT_ROWS) != 0) 3192 rowCount = 1; 3193 opt.scale = 1./(len * rowCount); 3194 } 3195 } 3196 3197 void apply(const uchar *src, uchar *dst) CV_OVERRIDE 3198 { 3199 opt.dft_func(opt, src, dst); 3200 } 3201 3202 void free() {} 3203 }; 3204 3205 struct ReplacementDFT1D : public hal::DFT1D 3206 { 3207 cvhalDFT *context; 3208 bool isInitialized; 3209 3210 ReplacementDFT1D() : context(0), isInitialized(false) {} 3211 bool init(int len, int count, int depth, int flags, bool *needBuffer) 3212 { 3213 int res = cv_hal_dftInit1D(&context, len, count, depth, flags, needBuffer); 3214 isInitialized = (res == CV_HAL_ERROR_OK); 3215 return isInitialized; 3216 } 3217 void apply(const uchar *src, uchar *dst) CV_OVERRIDE 3218 { 3219 if (isInitialized) 3220 { 3221 CALL_HAL(dft1D, cv_hal_dft1D, context, src, dst); 3222 } 3223 } 3224 ~ReplacementDFT1D() 3225 { 3226 if (isInitialized) 3227 { 3228 CALL_HAL(dftFree1D, cv_hal_dftFree1D, context); 3229 } 3230 } 3231 }; 3232 3233 struct ReplacementDFT2D : public hal::DFT2D 3234 { 3235 cvhalDFT *context; 3236 bool isInitialized; 3237 3238 ReplacementDFT2D() : context(0), isInitialized(false) {} 3239 bool init(int width, int height, int depth, 3240 int src_channels, int dst_channels, 3241 int flags, int nonzero_rows) 3242 { 3243 int res = cv_hal_dftInit2D(&context, width, height, depth, src_channels, dst_channels, flags, nonzero_rows); 3244 isInitialized = (res == CV_HAL_ERROR_OK); 3245 return isInitialized; 3246 } 3247 void apply(const uchar *src, size_t src_step, uchar *dst, size_t dst_step) CV_OVERRIDE 3248 { 3249 if (isInitialized) 3250 { 3251 CALL_HAL(dft2D, cv_hal_dft2D, context, src, src_step, dst, dst_step); 3252 } 3253 } 3254 ~ReplacementDFT2D() 3255 { 3256 if (isInitialized) 3257 { 3258 CALL_HAL(dftFree2D, cv_hal_dftFree1D, context); 3259 } 3260 } 3261 }; 3262 3263 namespace hal { 3264 3265 //================== 1D ====================== 3266 3267 Ptr<DFT1D> DFT1D::create(int len, int count, int depth, int flags, bool *needBuffer) 3268 { 3269 { 3270 ReplacementDFT1D *impl = new ReplacementDFT1D(); 3271 if (impl->init(len, count, depth, flags, needBuffer)) 3272 { 3273 return Ptr<DFT1D>(impl); 3274 } 3275 delete impl; 3276 } 3277 { 3278 OcvDftBasicImpl *impl = new OcvDftBasicImpl(); 3279 impl->init(len, count, depth, flags, needBuffer); 3280 return Ptr<DFT1D>(impl); 3281 } 3282 } 3283 3284 //================== 2D ====================== 3285 3286 Ptr<DFT2D> DFT2D::create(int width, int height, int depth, 3287 int src_channels, int dst_channels, 3288 int flags, int nonzero_rows) 3289 { 3290 { 3291 ReplacementDFT2D *impl = new ReplacementDFT2D(); 3292 if (impl->init(width, height, depth, src_channels, dst_channels, flags, nonzero_rows)) 3293 { 3294 return Ptr<DFT2D>(impl); 3295 } 3296 delete impl; 3297 } 3298 { 3299 if(width == 1 && nonzero_rows > 0 ) 3300 { 3301 CV_Error( CV_StsNotImplemented, 3302 "This mode (using nonzero_rows with a single-column matrix) breaks the function's logic, so it is prohibited.\n" 3303 "For fast convolution/correlation use 2-column matrix or single-row matrix instead" ); 3304 } 3305 OcvDftImpl *impl = new OcvDftImpl(); 3306 impl->init(width, height, depth, src_channels, dst_channels, flags, nonzero_rows); 3307 return Ptr<DFT2D>(impl); 3308 } 3309 } 3310 3311 } // cv::hal:: 3312 } // cv:: 3313 3314 3315 void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows ) 3316 { 3317 CV_INSTRUMENT_REGION(); 3318 3319 #ifdef HAVE_CLAMDFFT 3320 CV_OCL_RUN(ocl::haveAmdFft() && ocl::Device::getDefault().type() != ocl::Device::TYPE_CPU && 3321 _dst.isUMat() && _src0.dims() <= 2 && nonzero_rows == 0, 3322 ocl_dft_amdfft(_src0, _dst, flags)) 3323 #endif 3324 3325 #ifdef HAVE_OPENCL 3326 CV_OCL_RUN(_dst.isUMat() && _src0.dims() <= 2, 3327 ocl_dft(_src0, _dst, flags, nonzero_rows)) 3328 #endif 3329 3330 Mat src0 = _src0.getMat(), src = src0; 3331 bool inv = (flags & DFT_INVERSE) != 0; 3332 int type = src.type(); 3333 int depth = src.depth(); 3334 3335 CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 ); 3336 3337 // Fail if DFT_COMPLEX_INPUT is specified, but src is not 2 channels. 3338 CV_Assert( !((flags & DFT_COMPLEX_INPUT) && src.channels() != 2) ); 3339 3340 if( !inv && src.channels() == 1 && (flags & DFT_COMPLEX_OUTPUT) ) 3341 _dst.create( src.size(), CV_MAKETYPE(depth, 2) ); 3342 else if( inv && src.channels() == 2 && (flags & DFT_REAL_OUTPUT) ) 3343 _dst.create( src.size(), depth ); 3344 else 3345 _dst.create( src.size(), type ); 3346 3347 Mat dst = _dst.getMat(); 3348 3349 int f = 0; 3350 if (src.isContinuous() && dst.isContinuous()) 3351 f |= CV_HAL_DFT_IS_CONTINUOUS; 3352 if (inv) 3353 f |= CV_HAL_DFT_INVERSE; 3354 if (flags & DFT_ROWS) 3355 f |= CV_HAL_DFT_ROWS; 3356 if (flags & DFT_SCALE) 3357 f |= CV_HAL_DFT_SCALE; 3358 if (src.data == dst.data) 3359 f |= CV_HAL_DFT_IS_INPLACE; 3360 Ptr<hal::DFT2D> c = hal::DFT2D::create(src.cols, src.rows, depth, src.channels(), dst.channels(), f, nonzero_rows); 3361 c->apply(src.data, src.step, dst.data, dst.step); 3362 } 3363 3364 3365 void cv::idft( InputArray src, OutputArray dst, int flags, int nonzero_rows ) 3366 { 3367 CV_INSTRUMENT_REGION(); 3368 3369 dft( src, dst, flags | DFT_INVERSE, nonzero_rows ); 3370 } 3371 3372 #ifdef HAVE_OPENCL 3373 3374 namespace cv { 3375 3376 static bool ocl_mulSpectrums( InputArray _srcA, InputArray _srcB, 3377 OutputArray _dst, int flags, bool conjB ) 3378 { 3379 int atype = _srcA.type(), btype = _srcB.type(), 3380 rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1; 3381 Size asize = _srcA.size(), bsize = _srcB.size(); 3382 CV_Assert(asize == bsize); 3383 3384 if ( !(atype == CV_32FC2 && btype == CV_32FC2) || flags != 0 ) 3385 return false; 3386 3387 UMat A = _srcA.getUMat(), B = _srcB.getUMat(); 3388 CV_Assert(A.size() == B.size()); 3389 3390 _dst.create(A.size(), atype); 3391 UMat dst = _dst.getUMat(); 3392 3393 ocl::Kernel k("mulAndScaleSpectrums", 3394 ocl::core::mulspectrums_oclsrc, 3395 format("%s", conjB ? "-D CONJ" : "")); 3396 if (k.empty()) 3397 return false; 3398 3399 k.args(ocl::KernelArg::ReadOnlyNoSize(A), ocl::KernelArg::ReadOnlyNoSize(B), 3400 ocl::KernelArg::WriteOnly(dst), rowsPerWI); 3401 3402 size_t globalsize[2] = { (size_t)asize.width, ((size_t)asize.height + rowsPerWI - 1) / rowsPerWI }; 3403 return k.run(2, globalsize, NULL, false); 3404 } 3405 3406 } 3407 3408 #endif 3409 3410 namespace { 3411 3412 #define VAL(buf, elem) (((T*)((char*)data ## buf + (step ## buf * (elem))))[0]) 3413 #define MUL_SPECTRUMS_COL(A, B, C) \ 3414 VAL(C, 0) = VAL(A, 0) * VAL(B, 0); \ 3415 for (size_t j = 1; j <= rows - 2; j += 2) \ 3416 { \ 3417 double a_re = VAL(A, j), a_im = VAL(A, j + 1); \ 3418 double b_re = VAL(B, j), b_im = VAL(B, j + 1); \ 3419 if (conjB) b_im = -b_im; \ 3420 double c_re = a_re * b_re - a_im * b_im; \ 3421 double c_im = a_re * b_im + a_im * b_re; \ 3422 VAL(C, j) = (T)c_re; VAL(C, j + 1) = (T)c_im; \ 3423 } \ 3424 if ((rows & 1) == 0) \ 3425 VAL(C, rows-1) = VAL(A, rows-1) * VAL(B, rows-1) 3426 3427 template <typename T, bool conjB> static inline 3428 void mulSpectrums_processCol_noinplace(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows) 3429 { 3430 MUL_SPECTRUMS_COL(A, B, C); 3431 } 3432 3433 template <typename T, bool conjB> static inline 3434 void mulSpectrums_processCol_inplaceA(const T* dataB, T* dataAC, size_t stepB, size_t stepAC, size_t rows) 3435 { 3436 MUL_SPECTRUMS_COL(AC, B, AC); 3437 } 3438 template <typename T, bool conjB, bool inplaceA> static inline 3439 void mulSpectrums_processCol(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows) 3440 { 3441 if (inplaceA) 3442 mulSpectrums_processCol_inplaceA<T, conjB>(dataB, dataC, stepB, stepC, rows); 3443 else 3444 mulSpectrums_processCol_noinplace<T, conjB>(dataA, dataB, dataC, stepA, stepB, stepC, rows); 3445 } 3446 #undef MUL_SPECTRUMS_COL 3447 #undef VAL 3448 3449 template <typename T, bool conjB, bool inplaceA> static inline 3450 void mulSpectrums_processCols(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows, size_t cols) 3451 { 3452 mulSpectrums_processCol<T, conjB, inplaceA>(dataA, dataB, dataC, stepA, stepB, stepC, rows); 3453 if ((cols & 1) == 0) 3454 { 3455 mulSpectrums_processCol<T, conjB, inplaceA>(dataA + cols - 1, dataB + cols - 1, dataC + cols - 1, stepA, stepB, stepC, rows); 3456 } 3457 } 3458 3459 #define VAL(buf, elem) (data ## buf[(elem)]) 3460 #define MUL_SPECTRUMS_ROW(A, B, C) \ 3461 for (size_t j = j0; j < j1; j += 2) \ 3462 { \ 3463 double a_re = VAL(A, j), a_im = VAL(A, j + 1); \ 3464 double b_re = VAL(B, j), b_im = VAL(B, j + 1); \ 3465 if (conjB) b_im = -b_im; \ 3466 double c_re = a_re * b_re - a_im * b_im; \ 3467 double c_im = a_re * b_im + a_im * b_re; \ 3468 VAL(C, j) = (T)c_re; VAL(C, j + 1) = (T)c_im; \ 3469 } 3470 template <typename T, bool conjB> static inline 3471 void mulSpectrums_processRow_noinplace(const T* dataA, const T* dataB, T* dataC, size_t j0, size_t j1) 3472 { 3473 MUL_SPECTRUMS_ROW(A, B, C); 3474 } 3475 template <typename T, bool conjB> static inline 3476 void mulSpectrums_processRow_inplaceA(const T* dataB, T* dataAC, size_t j0, size_t j1) 3477 { 3478 MUL_SPECTRUMS_ROW(AC, B, AC); 3479 } 3480 template <typename T, bool conjB, bool inplaceA> static inline 3481 void mulSpectrums_processRow(const T* dataA, const T* dataB, T* dataC, size_t j0, size_t j1) 3482 { 3483 if (inplaceA) 3484 mulSpectrums_processRow_inplaceA<T, conjB>(dataB, dataC, j0, j1); 3485 else 3486 mulSpectrums_processRow_noinplace<T, conjB>(dataA, dataB, dataC, j0, j1); 3487 } 3488 #undef MUL_SPECTRUMS_ROW 3489 #undef VAL 3490 3491 template <typename T, bool conjB, bool inplaceA> static inline 3492 void mulSpectrums_processRows(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows, size_t cols, size_t j0, size_t j1, bool is_1d_CN1) 3493 { 3494 while (rows-- > 0) 3495 { 3496 if (is_1d_CN1) 3497 dataC[0] = dataA[0]*dataB[0]; 3498 mulSpectrums_processRow<T, conjB, inplaceA>(dataA, dataB, dataC, j0, j1); 3499 if (is_1d_CN1 && (cols & 1) == 0) 3500 dataC[j1] = dataA[j1]*dataB[j1]; 3501 3502 dataA = (const T*)(((char*)dataA) + stepA); 3503 dataB = (const T*)(((char*)dataB) + stepB); 3504 dataC = (T*)(((char*)dataC) + stepC); 3505 } 3506 } 3507 3508 3509 template <typename T, bool conjB, bool inplaceA> static inline 3510 void mulSpectrums_Impl_(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows, size_t cols, size_t j0, size_t j1, bool is_1d, bool isCN1) 3511 { 3512 if (!is_1d && isCN1) 3513 { 3514 mulSpectrums_processCols<T, conjB, inplaceA>(dataA, dataB, dataC, stepA, stepB, stepC, rows, cols); 3515 } 3516 mulSpectrums_processRows<T, conjB, inplaceA>(dataA, dataB, dataC, stepA, stepB, stepC, rows, cols, j0, j1, is_1d && isCN1); 3517 } 3518 template <typename T, bool conjB> static inline 3519 void mulSpectrums_Impl(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows, size_t cols, size_t j0, size_t j1, bool is_1d, bool isCN1) 3520 { 3521 if (dataA == dataC) 3522 mulSpectrums_Impl_<T, conjB, true>(dataA, dataB, dataC, stepA, stepB, stepC, rows, cols, j0, j1, is_1d, isCN1); 3523 else 3524 mulSpectrums_Impl_<T, conjB, false>(dataA, dataB, dataC, stepA, stepB, stepC, rows, cols, j0, j1, is_1d, isCN1); 3525 } 3526 3527 } // namespace 3528 3529 void cv::mulSpectrums( InputArray _srcA, InputArray _srcB, 3530 OutputArray _dst, int flags, bool conjB ) 3531 { 3532 CV_INSTRUMENT_REGION(); 3533 3534 CV_OCL_RUN(_dst.isUMat() && _srcA.dims() <= 2 && _srcB.dims() <= 2, 3535 ocl_mulSpectrums(_srcA, _srcB, _dst, flags, conjB)) 3536 3537 Mat srcA = _srcA.getMat(), srcB = _srcB.getMat(); 3538 int depth = srcA.depth(), cn = srcA.channels(), type = srcA.type(); 3539 size_t rows = srcA.rows, cols = srcA.cols; 3540 3541 CV_Assert( type == srcB.type() && srcA.size() == srcB.size() ); 3542 CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 ); 3543 3544 _dst.create( srcA.rows, srcA.cols, type ); 3545 Mat dst = _dst.getMat(); 3546 3547 // correct inplace support 3548 // Case 'dst.data == srcA.data' is handled by implementation, 3549 // because it is used frequently (filter2D, matchTemplate) 3550 if (dst.data == srcB.data) 3551 srcB = srcB.clone(); // workaround for B only 3552 3553 bool is_1d = (flags & DFT_ROWS) 3554 || (rows == 1) 3555 || (cols == 1 && srcA.isContinuous() && srcB.isContinuous() && dst.isContinuous()); 3556 3557 if( is_1d && !(flags & DFT_ROWS) ) 3558 cols = cols + rows - 1, rows = 1; 3559 3560 bool isCN1 = cn == 1; 3561 size_t j0 = isCN1 ? 1 : 0; 3562 size_t j1 = cols*cn - (((cols & 1) == 0 && cn == 1) ? 1 : 0); 3563 3564 if (depth == CV_32F) 3565 { 3566 const float* dataA = srcA.ptr<float>(); 3567 const float* dataB = srcB.ptr<float>(); 3568 float* dataC = dst.ptr<float>(); 3569 if (!conjB) 3570 mulSpectrums_Impl<float, false>(dataA, dataB, dataC, srcA.step, srcB.step, dst.step, rows, cols, j0, j1, is_1d, isCN1); 3571 else 3572 mulSpectrums_Impl<float, true>(dataA, dataB, dataC, srcA.step, srcB.step, dst.step, rows, cols, j0, j1, is_1d, isCN1); 3573 } 3574 else 3575 { 3576 const double* dataA = srcA.ptr<double>(); 3577 const double* dataB = srcB.ptr<double>(); 3578 double* dataC = dst.ptr<double>(); 3579 if (!conjB) 3580 mulSpectrums_Impl<double, false>(dataA, dataB, dataC, srcA.step, srcB.step, dst.step, rows, cols, j0, j1, is_1d, isCN1); 3581 else 3582 mulSpectrums_Impl<double, true>(dataA, dataB, dataC, srcA.step, srcB.step, dst.step, rows, cols, j0, j1, is_1d, isCN1); 3583 } 3584 } 3585 3586 3587 /****************************************************************************************\ 3588 Discrete Cosine Transform 3589 \****************************************************************************************/ 3590 3591 namespace cv 3592 { 3593 3594 /* DCT is calculated using DFT, as described here: 3595 http://www.ece.utexas.edu/~bevans/courses/ee381k/lectures/09_DCT/lecture9/: 3596 */ 3597 template<typename T> static void 3598 DCT( const OcvDftOptions & c, const T* src, size_t src_step, T* dft_src, T* dft_dst, T* dst, size_t dst_step, 3599 const Complex<T>* dct_wave ) 3600 { 3601 static const T sin_45 = (T)0.70710678118654752440084436210485; 3602 3603 int n = c.n; 3604 int j, n2 = n >> 1; 3605 3606 src_step /= sizeof(src[0]); 3607 dst_step /= sizeof(dst[0]); 3608 T* dst1 = dst + (n-1)*dst_step; 3609 3610 if( n == 1 ) 3611 { 3612 dst[0] = src[0]; 3613 return; 3614 } 3615 3616 for( j = 0; j < n2; j++, src += src_step*2 ) 3617 { 3618 dft_src[j] = src[0]; 3619 dft_src[n-j-1] = src[src_step]; 3620 } 3621 3622 RealDFT(c, dft_src, dft_dst); 3623 src = dft_dst; 3624 3625 dst[0] = (T)(src[0]*dct_wave->re*sin_45); 3626 dst += dst_step; 3627 for( j = 1, dct_wave++; j < n2; j++, dct_wave++, 3628 dst += dst_step, dst1 -= dst_step ) 3629 { 3630 T t0 = dct_wave->re*src[j*2-1] - dct_wave->im*src[j*2]; 3631 T t1 = -dct_wave->im*src[j*2-1] - dct_wave->re*src[j*2]; 3632 dst[0] = t0; 3633 dst1[0] = t1; 3634 } 3635 3636 dst[0] = src[n-1]*dct_wave->re; 3637 } 3638 3639 3640 template<typename T> static void 3641 IDCT( const OcvDftOptions & c, const T* src, size_t src_step, T* dft_src, T* dft_dst, T* dst, size_t dst_step, 3642 const Complex<T>* dct_wave) 3643 { 3644 static const T sin_45 = (T)0.70710678118654752440084436210485; 3645 int n = c.n; 3646 int j, n2 = n >> 1; 3647 3648 src_step /= sizeof(src[0]); 3649 dst_step /= sizeof(dst[0]); 3650 const T* src1 = src + (n-1)*src_step; 3651 3652 if( n == 1 ) 3653 { 3654 dst[0] = src[0]; 3655 return; 3656 } 3657 3658 dft_src[0] = (T)(src[0]*2*dct_wave->re*sin_45); 3659 src += src_step; 3660 for( j = 1, dct_wave++; j < n2; j++, dct_wave++, 3661 src += src_step, src1 -= src_step ) 3662 { 3663 T t0 = dct_wave->re*src[0] - dct_wave->im*src1[0]; 3664 T t1 = -dct_wave->im*src[0] - dct_wave->re*src1[0]; 3665 dft_src[j*2-1] = t0; 3666 dft_src[j*2] = t1; 3667 } 3668 3669 dft_src[n-1] = (T)(src[0]*2*dct_wave->re); 3670 CCSIDFT(c, dft_src, dft_dst); 3671 3672 for( j = 0; j < n2; j++, dst += dst_step*2 ) 3673 { 3674 dst[0] = dft_dst[j]; 3675 dst[dst_step] = dft_dst[n-j-1]; 3676 } 3677 } 3678 3679 3680 static void 3681 DCTInit( int n, int elem_size, void* _wave, int inv ) 3682 { 3683 static const double DctScale[] = 3684 { 3685 0.707106781186547570, 0.500000000000000000, 0.353553390593273790, 3686 0.250000000000000000, 0.176776695296636890, 0.125000000000000000, 3687 0.088388347648318447, 0.062500000000000000, 0.044194173824159223, 3688 0.031250000000000000, 0.022097086912079612, 0.015625000000000000, 3689 0.011048543456039806, 0.007812500000000000, 0.005524271728019903, 3690 0.003906250000000000, 0.002762135864009952, 0.001953125000000000, 3691 0.001381067932004976, 0.000976562500000000, 0.000690533966002488, 3692 0.000488281250000000, 0.000345266983001244, 0.000244140625000000, 3693 0.000172633491500622, 0.000122070312500000, 0.000086316745750311, 3694 0.000061035156250000, 0.000043158372875155, 0.000030517578125000 3695 }; 3696 3697 int i; 3698 Complex<double> w, w1; 3699 double t, scale; 3700 3701 if( n == 1 ) 3702 return; 3703 3704 assert( (n&1) == 0 ); 3705 3706 if( (n & (n - 1)) == 0 ) 3707 { 3708 int m; 3709 for( m = 0; (unsigned)(1 << m) < (unsigned)n; m++ ) 3710 ; 3711 scale = (!inv ? 2 : 1)*DctScale[m]; 3712 w1.re = DFTTab[m+2][0]; 3713 w1.im = -DFTTab[m+2][1]; 3714 } 3715 else 3716 { 3717 t = 1./(2*n); 3718 scale = (!inv ? 2 : 1)*std::sqrt(t); 3719 w1.im = sin(-CV_PI*t); 3720 w1.re = std::sqrt(1. - w1.im*w1.im); 3721 } 3722 n >>= 1; 3723 3724 if( elem_size == sizeof(Complex<double>) ) 3725 { 3726 Complex<double>* wave = (Complex<double>*)_wave; 3727 3728 w.re = scale; 3729 w.im = 0.; 3730 3731 for( i = 0; i <= n; i++ ) 3732 { 3733 wave[i] = w; 3734 t = w.re*w1.re - w.im*w1.im; 3735 w.im = w.re*w1.im + w.im*w1.re; 3736 w.re = t; 3737 } 3738 } 3739 else 3740 { 3741 Complex<float>* wave = (Complex<float>*)_wave; 3742 assert( elem_size == sizeof(Complex<float>) ); 3743 3744 w.re = (float)scale; 3745 w.im = 0.f; 3746 3747 for( i = 0; i <= n; i++ ) 3748 { 3749 wave[i].re = (float)w.re; 3750 wave[i].im = (float)w.im; 3751 t = w.re*w1.re - w.im*w1.im; 3752 w.im = w.re*w1.im + w.im*w1.re; 3753 w.re = t; 3754 } 3755 } 3756 } 3757 3758 3759 typedef void (*DCTFunc)(const OcvDftOptions & c, const void* src, size_t src_step, void* dft_src, 3760 void* dft_dst, void* dst, size_t dst_step, const void* dct_wave); 3761 3762 static void DCT_32f(const OcvDftOptions & c, const float* src, size_t src_step, float* dft_src, float* dft_dst, 3763 float* dst, size_t dst_step, const Complexf* dct_wave) 3764 { 3765 DCT(c, src, src_step, dft_src, dft_dst, dst, dst_step, dct_wave); 3766 } 3767 3768 static void IDCT_32f(const OcvDftOptions & c, const float* src, size_t src_step, float* dft_src, float* dft_dst, 3769 float* dst, size_t dst_step, const Complexf* dct_wave) 3770 { 3771 IDCT(c, src, src_step, dft_src, dft_dst, dst, dst_step, dct_wave); 3772 } 3773 3774 static void DCT_64f(const OcvDftOptions & c, const double* src, size_t src_step, double* dft_src, double* dft_dst, 3775 double* dst, size_t dst_step, const Complexd* dct_wave) 3776 { 3777 DCT(c, src, src_step, dft_src, dft_dst, dst, dst_step, dct_wave); 3778 } 3779 3780 static void IDCT_64f(const OcvDftOptions & c, const double* src, size_t src_step, double* dft_src, double* dft_dst, 3781 double* dst, size_t dst_step, const Complexd* dct_wave) 3782 { 3783 IDCT(c, src, src_step, dft_src, dft_dst, dst, dst_step, dct_wave); 3784 } 3785 3786 } 3787 3788 #ifdef HAVE_IPP 3789 namespace cv 3790 { 3791 3792 #if IPP_VERSION_X100 >= 900 3793 typedef IppStatus (CV_STDCALL * ippiDCTFunc)(const Ipp32f* pSrc, int srcStep, Ipp32f* pDst, int dstStep, const void* pDCTSpec, Ipp8u* pBuffer); 3794 typedef IppStatus (CV_STDCALL * ippiDCTInit)(void* pDCTSpec, IppiSize roiSize, Ipp8u* pMemInit ); 3795 typedef IppStatus (CV_STDCALL * ippiDCTGetSize)(IppiSize roiSize, int* pSizeSpec, int* pSizeInit, int* pSizeBuf); 3796 #elif IPP_VERSION_X100 >= 700 3797 typedef IppStatus (CV_STDCALL * ippiDCTFunc)(const Ipp32f*, int, Ipp32f*, int, const void*, Ipp8u*); 3798 typedef IppStatus (CV_STDCALL * ippiDCTInitAlloc)(void**, IppiSize, IppHintAlgorithm); 3799 typedef IppStatus (CV_STDCALL * ippiDCTFree)(void* pDCTSpec); 3800 typedef IppStatus (CV_STDCALL * ippiDCTGetBufSize)(const void*, int*); 3801 #endif 3802 3803 class DctIPPLoop_Invoker : public ParallelLoopBody 3804 { 3805 public: 3806 DctIPPLoop_Invoker(const uchar * _src, size_t _src_step, uchar * _dst, size_t _dst_step, int _width, bool _inv, bool *_ok) : 3807 ParallelLoopBody(), src(_src), src_step(_src_step), dst(_dst), dst_step(_dst_step), width(_width), inv(_inv), ok(_ok) 3808 { 3809 *ok = true; 3810 } 3811 3812 virtual void operator()(const Range& range) const CV_OVERRIDE 3813 { 3814 if(*ok == false) 3815 return; 3816 3817 #if IPP_VERSION_X100 >= 900 3818 IppiSize srcRoiSize = {width, 1}; 3819 3820 int specSize = 0; 3821 int initSize = 0; 3822 int bufferSize = 0; 3823 3824 Ipp8u* pDCTSpec = NULL; 3825 Ipp8u* pBuffer = NULL; 3826 Ipp8u* pInitBuf = NULL; 3827 3828 #define IPP_RETURN \ 3829 if(pDCTSpec) \ 3830 ippFree(pDCTSpec); \ 3831 if(pBuffer) \ 3832 ippFree(pBuffer); \ 3833 if(pInitBuf) \ 3834 ippFree(pInitBuf); \ 3835 return; 3836 3837 ippiDCTFunc ippiDCT_32f_C1R = inv ? (ippiDCTFunc)ippiDCTInv_32f_C1R : (ippiDCTFunc)ippiDCTFwd_32f_C1R; 3838 ippiDCTInit ippDctInit = inv ? (ippiDCTInit)ippiDCTInvInit_32f : (ippiDCTInit)ippiDCTFwdInit_32f; 3839 ippiDCTGetSize ippDctGetSize = inv ? (ippiDCTGetSize)ippiDCTInvGetSize_32f : (ippiDCTGetSize)ippiDCTFwdGetSize_32f; 3840 3841 if(ippDctGetSize(srcRoiSize, &specSize, &initSize, &bufferSize) < 0) 3842 { 3843 *ok = false; 3844 return; 3845 } 3846 3847 pDCTSpec = (Ipp8u*)CV_IPP_MALLOC(specSize); 3848 if(!pDCTSpec && specSize) 3849 { 3850 *ok = false; 3851 return; 3852 } 3853 3854 pBuffer = (Ipp8u*)CV_IPP_MALLOC(bufferSize); 3855 if(!pBuffer && bufferSize) 3856 { 3857 *ok = false; 3858 IPP_RETURN 3859 } 3860 pInitBuf = (Ipp8u*)CV_IPP_MALLOC(initSize); 3861 if(!pInitBuf && initSize) 3862 { 3863 *ok = false; 3864 IPP_RETURN 3865 } 3866 3867 if(ippDctInit(pDCTSpec, srcRoiSize, pInitBuf) < 0) 3868 { 3869 *ok = false; 3870 IPP_RETURN 3871 } 3872 3873 for(int i = range.start; i < range.end; ++i) 3874 { 3875 if(CV_INSTRUMENT_FUN_IPP(ippiDCT_32f_C1R, (float*)(src + src_step * i), static_cast<int>(src_step), (float*)(dst + dst_step * i), static_cast<int>(dst_step), pDCTSpec, pBuffer) < 0) 3876 { 3877 *ok = false; 3878 IPP_RETURN 3879 } 3880 } 3881 IPP_RETURN 3882 #undef IPP_RETURN 3883 #elif IPP_VERSION_X100 >= 700 3884 void* pDCTSpec; 3885 AutoBuffer<uchar> buf; 3886 uchar* pBuffer = 0; 3887 int bufSize=0; 3888 3889 IppiSize srcRoiSize = {width, 1}; 3890 3891 CV_SUPPRESS_DEPRECATED_START 3892 3893 ippiDCTFunc ippDctFun = inv ? (ippiDCTFunc)ippiDCTInv_32f_C1R : (ippiDCTFunc)ippiDCTFwd_32f_C1R; 3894 ippiDCTInitAlloc ippInitAlloc = inv ? (ippiDCTInitAlloc)ippiDCTInvInitAlloc_32f : (ippiDCTInitAlloc)ippiDCTFwdInitAlloc_32f; 3895 ippiDCTFree ippFree = inv ? (ippiDCTFree)ippiDCTInvFree_32f : (ippiDCTFree)ippiDCTFwdFree_32f; 3896 ippiDCTGetBufSize ippGetBufSize = inv ? (ippiDCTGetBufSize)ippiDCTInvGetBufSize_32f : (ippiDCTGetBufSize)ippiDCTFwdGetBufSize_32f; 3897 3898 if (ippInitAlloc(&pDCTSpec, srcRoiSize, ippAlgHintNone)>=0 && ippGetBufSize(pDCTSpec, &bufSize)>=0) 3899 { 3900 buf.allocate( bufSize ); 3901 pBuffer = (uchar*)buf; 3902 3903 for( int i = range.start; i < range.end; ++i) 3904 { 3905 if(ippDctFun((float*)(src + src_step * i), static_cast<int>(src_step), (float*)(dst + dst_step * i), static_cast<int>(dst_step), pDCTSpec, (Ipp8u*)pBuffer) < 0) 3906 { 3907 *ok = false; 3908 break; 3909 } 3910 } 3911 } 3912 else 3913 *ok = false; 3914 3915 if (pDCTSpec) 3916 ippFree(pDCTSpec); 3917 3918 CV_SUPPRESS_DEPRECATED_END 3919 #else 3920 CV_UNUSED(range); 3921 *ok = false; 3922 #endif 3923 } 3924 3925 private: 3926 const uchar * src; 3927 size_t src_step; 3928 uchar * dst; 3929 size_t dst_step; 3930 int width; 3931 bool inv; 3932 bool *ok; 3933 }; 3934 3935 static bool DctIPPLoop(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, bool inv) 3936 { 3937 bool ok; 3938 parallel_for_(Range(0, height), DctIPPLoop_Invoker(src, src_step, dst, dst_step, width, inv, &ok), height/(double)(1<<4) ); 3939 return ok; 3940 } 3941 3942 static bool ippi_DCT_32f(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, bool inv, bool row) 3943 { 3944 CV_INSTRUMENT_REGION_IPP(); 3945 3946 if(row) 3947 return DctIPPLoop(src, src_step, dst, dst_step, width, height, inv); 3948 else 3949 { 3950 #if IPP_VERSION_X100 >= 900 3951 IppiSize srcRoiSize = {width, height}; 3952 3953 int specSize = 0; 3954 int initSize = 0; 3955 int bufferSize = 0; 3956 3957 Ipp8u* pDCTSpec = NULL; 3958 Ipp8u* pBuffer = NULL; 3959 Ipp8u* pInitBuf = NULL; 3960 3961 #define IPP_RELEASE \ 3962 if(pDCTSpec) \ 3963 ippFree(pDCTSpec); \ 3964 if(pBuffer) \ 3965 ippFree(pBuffer); \ 3966 if(pInitBuf) \ 3967 ippFree(pInitBuf); \ 3968 3969 ippiDCTFunc ippiDCT_32f_C1R = inv ? (ippiDCTFunc)ippiDCTInv_32f_C1R : (ippiDCTFunc)ippiDCTFwd_32f_C1R; 3970 ippiDCTInit ippDctInit = inv ? (ippiDCTInit)ippiDCTInvInit_32f : (ippiDCTInit)ippiDCTFwdInit_32f; 3971 ippiDCTGetSize ippDctGetSize = inv ? (ippiDCTGetSize)ippiDCTInvGetSize_32f : (ippiDCTGetSize)ippiDCTFwdGetSize_32f; 3972 3973 if(ippDctGetSize(srcRoiSize, &specSize, &initSize, &bufferSize) < 0) 3974 return false; 3975 3976 pDCTSpec = (Ipp8u*)CV_IPP_MALLOC(specSize); 3977 if(!pDCTSpec && specSize) 3978 return false; 3979 3980 pBuffer = (Ipp8u*)CV_IPP_MALLOC(bufferSize); 3981 if(!pBuffer && bufferSize) 3982 { 3983 IPP_RELEASE 3984 return false; 3985 } 3986 pInitBuf = (Ipp8u*)CV_IPP_MALLOC(initSize); 3987 if(!pInitBuf && initSize) 3988 { 3989 IPP_RELEASE 3990 return false; 3991 } 3992 3993 if(ippDctInit(pDCTSpec, srcRoiSize, pInitBuf) < 0) 3994 { 3995 IPP_RELEASE 3996 return false; 3997 } 3998 3999 if(CV_INSTRUMENT_FUN_IPP(ippiDCT_32f_C1R, (float*)src, static_cast<int>(src_step), (float*)dst, static_cast<int>(dst_step), pDCTSpec, pBuffer) < 0) 4000 { 4001 IPP_RELEASE 4002 return false; 4003 } 4004 4005 IPP_RELEASE 4006 return true; 4007 #undef IPP_RELEASE 4008 #elif IPP_VERSION_X100 >= 700 4009 IppStatus status; 4010 void* pDCTSpec; 4011 AutoBuffer<uchar> buf; 4012 uchar* pBuffer = 0; 4013 int bufSize=0; 4014 4015 IppiSize srcRoiSize = {width, height}; 4016 4017 CV_SUPPRESS_DEPRECATED_START 4018 4019 ippiDCTFunc ippDctFun = inv ? (ippiDCTFunc)ippiDCTInv_32f_C1R : (ippiDCTFunc)ippiDCTFwd_32f_C1R; 4020 ippiDCTInitAlloc ippInitAlloc = inv ? (ippiDCTInitAlloc)ippiDCTInvInitAlloc_32f : (ippiDCTInitAlloc)ippiDCTFwdInitAlloc_32f; 4021 ippiDCTFree ippFree = inv ? (ippiDCTFree)ippiDCTInvFree_32f : (ippiDCTFree)ippiDCTFwdFree_32f; 4022 ippiDCTGetBufSize ippGetBufSize = inv ? (ippiDCTGetBufSize)ippiDCTInvGetBufSize_32f : (ippiDCTGetBufSize)ippiDCTFwdGetBufSize_32f; 4023 4024 status = ippStsErr; 4025 4026 if (ippInitAlloc(&pDCTSpec, srcRoiSize, ippAlgHintNone)>=0 && ippGetBufSize(pDCTSpec, &bufSize)>=0) 4027 { 4028 buf.allocate( bufSize ); 4029 pBuffer = (uchar*)buf; 4030 4031 status = ippDctFun((float*)src, static_cast<int>(src_step), (float*)dst, static_cast<int>(dst_step), pDCTSpec, (Ipp8u*)pBuffer); 4032 } 4033 4034 if (pDCTSpec) 4035 ippFree(pDCTSpec); 4036 4037 CV_SUPPRESS_DEPRECATED_END 4038 4039 return status >= 0; 4040 #else 4041 CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(inv); CV_UNUSED(row); 4042 return false; 4043 #endif 4044 } 4045 } 4046 } 4047 #endif 4048 4049 namespace cv { 4050 4051 class OcvDctImpl CV_FINAL : public hal::DCT2D 4052 { 4053 public: 4054 OcvDftOptions opt; 4055 4056 int _factors[34]; 4057 AutoBuffer<uint> wave_buf; 4058 AutoBuffer<int> itab_buf; 4059 4060 DCTFunc dct_func; 4061 bool isRowTransform; 4062 bool isInverse; 4063 bool isContinuous; 4064 int start_stage; 4065 int end_stage; 4066 int width; 4067 int height; 4068 int depth; 4069 4070 void init(int _width, int _height, int _depth, int flags) 4071 { 4072 width = _width; 4073 height = _height; 4074 depth = _depth; 4075 isInverse = (flags & CV_HAL_DFT_INVERSE) != 0; 4076 isRowTransform = (flags & CV_HAL_DFT_ROWS) != 0; 4077 isContinuous = (flags & CV_HAL_DFT_IS_CONTINUOUS) != 0; 4078 static DCTFunc dct_tbl[4] = 4079 { 4080 (DCTFunc)DCT_32f, 4081 (DCTFunc)IDCT_32f, 4082 (DCTFunc)DCT_64f, 4083 (DCTFunc)IDCT_64f 4084 }; 4085 dct_func = dct_tbl[(int)isInverse + (depth == CV_64F)*2]; 4086 opt.nf = 0; 4087 opt.isComplex = false; 4088 opt.isInverse = false; 4089 opt.noPermute = false; 4090 opt.scale = 1.; 4091 opt.factors = _factors; 4092 4093 if (isRowTransform || height == 1 || (width == 1 && isContinuous)) 4094 { 4095 start_stage = end_stage = 0; 4096 } 4097 else 4098 { 4099 start_stage = (width == 1); 4100 end_stage = 1; 4101 } 4102 } 4103 void apply(const uchar *src, size_t src_step, uchar *dst, size_t dst_step) CV_OVERRIDE 4104 { 4105 CV_IPP_RUN(IPP_VERSION_X100 >= 700 && depth == CV_32F, ippi_DCT_32f(src, src_step, dst, dst_step, width, height, isInverse, isRowTransform)) 4106 4107 AutoBuffer<uchar> dct_wave; 4108 AutoBuffer<uchar> src_buf, dst_buf; 4109 uchar *src_dft_buf = 0, *dst_dft_buf = 0; 4110 int prev_len = 0; 4111 int elem_size = (depth == CV_32F) ? sizeof(float) : sizeof(double); 4112 int complex_elem_size = elem_size*2; 4113 4114 for(int stage = start_stage ; stage <= end_stage; stage++ ) 4115 { 4116 const uchar* sptr = src; 4117 uchar* dptr = dst; 4118 size_t sstep0, sstep1, dstep0, dstep1; 4119 int len, count; 4120 4121 if( stage == 0 ) 4122 { 4123 len = width; 4124 count = height; 4125 if( len == 1 && !isRowTransform ) 4126 { 4127 len = height; 4128 count = 1; 4129 } 4130 sstep0 = src_step; 4131 dstep0 = dst_step; 4132 sstep1 = dstep1 = elem_size; 4133 } 4134 else 4135 { 4136 len = height; 4137 count = width; 4138 sstep1 = src_step; 4139 dstep1 = dst_step; 4140 sstep0 = dstep0 = elem_size; 4141 } 4142 4143 opt.n = len; 4144 opt.tab_size = len; 4145 4146 if( len != prev_len ) 4147 { 4148 if( len > 1 && (len & 1) ) 4149 CV_Error( CV_StsNotImplemented, "Odd-size DCT\'s are not implemented" ); 4150 4151 opt.nf = DFTFactorize( len, opt.factors ); 4152 bool inplace_transform = opt.factors[0] == opt.factors[opt.nf-1]; 4153 4154 wave_buf.allocate(len*complex_elem_size); 4155 opt.wave = wave_buf.data(); 4156 itab_buf.allocate(len); 4157 opt.itab = itab_buf.data(); 4158 DFTInit( len, opt.nf, opt.factors, opt.itab, complex_elem_size, opt.wave, isInverse ); 4159 4160 dct_wave.allocate((len/2 + 1)*complex_elem_size); 4161 src_buf.allocate(len*elem_size); 4162 src_dft_buf = src_buf.data(); 4163 if(!inplace_transform) 4164 { 4165 dst_buf.allocate(len*elem_size); 4166 dst_dft_buf = dst_buf.data(); 4167 } 4168 else 4169 { 4170 dst_dft_buf = src_buf.data(); 4171 } 4172 DCTInit( len, complex_elem_size, dct_wave.data(), isInverse); 4173 prev_len = len; 4174 } 4175 // otherwise reuse the tables calculated on the previous stage 4176 for(unsigned i = 0; i < static_cast<unsigned>(count); i++ ) 4177 { 4178 dct_func( opt, sptr + i*sstep0, sstep1, src_dft_buf, dst_dft_buf, 4179 dptr + i*dstep0, dstep1, dct_wave.data()); 4180 } 4181 src = dst; 4182 src_step = dst_step; 4183 } 4184 } 4185 }; 4186 4187 struct ReplacementDCT2D : public hal::DCT2D 4188 { 4189 cvhalDFT *context; 4190 bool isInitialized; 4191 4192 ReplacementDCT2D() : context(0), isInitialized(false) {} 4193 bool init(int width, int height, int depth, int flags) 4194 { 4195 int res = hal_ni_dctInit2D(&context, width, height, depth, flags); 4196 isInitialized = (res == CV_HAL_ERROR_OK); 4197 return isInitialized; 4198 } 4199 void apply(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step) CV_OVERRIDE 4200 { 4201 if (isInitialized) 4202 { 4203 CALL_HAL(dct2D, cv_hal_dct2D, context, src_data, src_step, dst_data, dst_step); 4204 } 4205 } 4206 ~ReplacementDCT2D() 4207 { 4208 if (isInitialized) 4209 { 4210 CALL_HAL(dctFree2D, cv_hal_dctFree2D, context); 4211 } 4212 } 4213 }; 4214 4215 namespace hal { 4216 4217 Ptr<DCT2D> DCT2D::create(int width, int height, int depth, int flags) 4218 { 4219 { 4220 ReplacementDCT2D *impl = new ReplacementDCT2D(); 4221 if (impl->init(width, height, depth, flags)) 4222 { 4223 return Ptr<DCT2D>(impl); 4224 } 4225 delete impl; 4226 } 4227 { 4228 OcvDctImpl *impl = new OcvDctImpl(); 4229 impl->init(width, height, depth, flags); 4230 return Ptr<DCT2D>(impl); 4231 } 4232 } 4233 4234 } // cv::hal:: 4235 } // cv:: 4236 4237 void cv::dct( InputArray _src0, OutputArray _dst, int flags ) 4238 { 4239 CV_INSTRUMENT_REGION(); 4240 4241 Mat src0 = _src0.getMat(), src = src0; 4242 int type = src.type(), depth = src.depth(); 4243 4244 CV_Assert( type == CV_32FC1 || type == CV_64FC1 ); 4245 _dst.create( src.rows, src.cols, type ); 4246 Mat dst = _dst.getMat(); 4247 4248 int f = 0; 4249 if ((flags & DFT_ROWS) != 0) 4250 f |= CV_HAL_DFT_ROWS; 4251 if ((flags & DCT_INVERSE) != 0) 4252 f |= CV_HAL_DFT_INVERSE; 4253 if (src.isContinuous() && dst.isContinuous()) 4254 f |= CV_HAL_DFT_IS_CONTINUOUS; 4255 4256 Ptr<hal::DCT2D> c = hal::DCT2D::create(src.cols, src.rows, depth, f); 4257 c->apply(src.data, src.step, dst.data, dst.step); 4258 } 4259 4260 4261 void cv::idct( InputArray src, OutputArray dst, int flags ) 4262 { 4263 CV_INSTRUMENT_REGION(); 4264 4265 dct( src, dst, flags | DCT_INVERSE ); 4266 } 4267 4268 namespace cv 4269 { 4270 4271 static const int optimalDFTSizeTab[] = { 4272 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 4273 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 4274 162, 180, 192, 200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 4275 384, 400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720, 4276 729, 750, 768, 800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125, 1152, 1200, 4277 1215, 1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536, 1600, 1620, 1728, 1800, 1875, 4278 1920, 1944, 2000, 2025, 2048, 2160, 2187, 2250, 2304, 2400, 2430, 2500, 2560, 2592, 4279 2700, 2880, 2916, 3000, 3072, 3125, 3200, 3240, 3375, 3456, 3600, 3645, 3750, 3840, 4280 3888, 4000, 4050, 4096, 4320, 4374, 4500, 4608, 4800, 4860, 5000, 5120, 5184, 5400, 4281 5625, 5760, 5832, 6000, 6075, 6144, 6250, 6400, 6480, 6561, 6750, 6912, 7200, 7290, 4282 7500, 7680, 7776, 8000, 8100, 8192, 8640, 8748, 9000, 9216, 9375, 9600, 9720, 10000, 4283 10125, 10240, 10368, 10800, 10935, 11250, 11520, 11664, 12000, 12150, 12288, 12500, 4284 12800, 12960, 13122, 13500, 13824, 14400, 14580, 15000, 15360, 15552, 15625, 16000, 4285 16200, 16384, 16875, 17280, 17496, 18000, 18225, 18432, 18750, 19200, 19440, 19683, 4286 20000, 20250, 20480, 20736, 21600, 21870, 22500, 23040, 23328, 24000, 24300, 24576, 4287 25000, 25600, 25920, 26244, 27000, 27648, 28125, 28800, 29160, 30000, 30375, 30720, 4288 31104, 31250, 32000, 32400, 32768, 32805, 33750, 34560, 34992, 36000, 36450, 36864, 4289 37500, 38400, 38880, 39366, 40000, 40500, 40960, 41472, 43200, 43740, 45000, 46080, 4290 46656, 46875, 48000, 48600, 49152, 50000, 50625, 51200, 51840, 52488, 54000, 54675, 4291 55296, 56250, 57600, 58320, 59049, 60000, 60750, 61440, 62208, 62500, 64000, 64800, 4292 65536, 65610, 67500, 69120, 69984, 72000, 72900, 73728, 75000, 76800, 77760, 78125, 4293 78732, 80000, 81000, 81920, 82944, 84375, 86400, 87480, 90000, 91125, 92160, 93312, 4294 93750, 96000, 97200, 98304, 98415, 100000, 101250, 102400, 103680, 104976, 108000, 4295 109350, 110592, 112500, 115200, 116640, 118098, 120000, 121500, 122880, 124416, 125000, 4296 128000, 129600, 131072, 131220, 135000, 138240, 139968, 140625, 144000, 145800, 147456, 4297 150000, 151875, 153600, 155520, 156250, 157464, 160000, 162000, 163840, 164025, 165888, 4298 168750, 172800, 174960, 177147, 180000, 182250, 184320, 186624, 187500, 192000, 194400, 4299 196608, 196830, 200000, 202500, 204800, 207360, 209952, 216000, 218700, 221184, 225000, 4300 230400, 233280, 234375, 236196, 240000, 243000, 245760, 248832, 250000, 253125, 256000, 4301 259200, 262144, 262440, 270000, 273375, 276480, 279936, 281250, 288000, 291600, 294912, 4302 295245, 300000, 303750, 307200, 311040, 312500, 314928, 320000, 324000, 327680, 328050, 4303 331776, 337500, 345600, 349920, 354294, 360000, 364500, 368640, 373248, 375000, 384000, 4304 388800, 390625, 393216, 393660, 400000, 405000, 409600, 414720, 419904, 421875, 432000, 4305 437400, 442368, 450000, 455625, 460800, 466560, 468750, 472392, 480000, 486000, 491520, 4306 492075, 497664, 500000, 506250, 512000, 518400, 524288, 524880, 531441, 540000, 546750, 4307 552960, 559872, 562500, 576000, 583200, 589824, 590490, 600000, 607500, 614400, 622080, 4308 625000, 629856, 640000, 648000, 655360, 656100, 663552, 675000, 691200, 699840, 703125, 4309 708588, 720000, 729000, 737280, 746496, 750000, 759375, 768000, 777600, 781250, 786432, 4310 787320, 800000, 810000, 819200, 820125, 829440, 839808, 843750, 864000, 874800, 884736, 4311 885735, 900000, 911250, 921600, 933120, 937500, 944784, 960000, 972000, 983040, 984150, 4312 995328, 1000000, 1012500, 1024000, 1036800, 1048576, 1049760, 1062882, 1080000, 1093500, 4313 1105920, 1119744, 1125000, 1152000, 1166400, 1171875, 1179648, 1180980, 1200000, 4314 1215000, 1228800, 1244160, 1250000, 1259712, 1265625, 1280000, 1296000, 1310720, 4315 1312200, 1327104, 1350000, 1366875, 1382400, 1399680, 1406250, 1417176, 1440000, 4316 1458000, 1474560, 1476225, 1492992, 1500000, 1518750, 1536000, 1555200, 1562500, 4317 1572864, 1574640, 1594323, 1600000, 1620000, 1638400, 1640250, 1658880, 1679616, 4318 1687500, 1728000, 1749600, 1769472, 1771470, 1800000, 1822500, 1843200, 1866240, 4319 1875000, 1889568, 1920000, 1944000, 1953125, 1966080, 1968300, 1990656, 2000000, 4320 2025000, 2048000, 2073600, 2097152, 2099520, 2109375, 2125764, 2160000, 2187000, 4321 2211840, 2239488, 2250000, 2278125, 2304000, 2332800, 2343750, 2359296, 2361960, 4322 2400000, 2430000, 2457600, 2460375, 2488320, 2500000, 2519424, 2531250, 2560000, 4323 2592000, 2621440, 2624400, 2654208, 2657205, 2700000, 2733750, 2764800, 2799360, 4324 2812500, 2834352, 2880000, 2916000, 2949120, 2952450, 2985984, 3000000, 3037500, 4325 3072000, 3110400, 3125000, 3145728, 3149280, 3188646, 3200000, 3240000, 3276800, 4326 3280500, 3317760, 3359232, 3375000, 3456000, 3499200, 3515625, 3538944, 3542940, 4327 3600000, 3645000, 3686400, 3732480, 3750000, 3779136, 3796875, 3840000, 3888000, 4328 3906250, 3932160, 3936600, 3981312, 4000000, 4050000, 4096000, 4100625, 4147200, 4329 4194304, 4199040, 4218750, 4251528, 4320000, 4374000, 4423680, 4428675, 4478976, 4330 4500000, 4556250, 4608000, 4665600, 4687500, 4718592, 4723920, 4782969, 4800000, 4331 4860000, 4915200, 4920750, 4976640, 5000000, 5038848, 5062500, 5120000, 5184000, 4332 5242880, 5248800, 5308416, 5314410, 5400000, 5467500, 5529600, 5598720, 5625000, 4333 5668704, 5760000, 5832000, 5859375, 5898240, 5904900, 5971968, 6000000, 6075000, 4334 6144000, 6220800, 6250000, 6291456, 6298560, 6328125, 6377292, 6400000, 6480000, 4335 6553600, 6561000, 6635520, 6718464, 6750000, 6834375, 6912000, 6998400, 7031250, 4336 7077888, 7085880, 7200000, 7290000, 7372800, 7381125, 7464960, 7500000, 7558272, 4337 7593750, 7680000, 7776000, 7812500, 7864320, 7873200, 7962624, 7971615, 8000000, 4338 8100000, 8192000, 8201250, 8294400, 8388608, 8398080, 8437500, 8503056, 8640000, 4339 8748000, 8847360, 8857350, 8957952, 9000000, 9112500, 9216000, 9331200, 9375000, 4340 9437184, 9447840, 9565938, 9600000, 9720000, 9765625, 9830400, 9841500, 9953280, 4341 10000000, 10077696, 10125000, 10240000, 10368000, 10485760, 10497600, 10546875, 10616832, 4342 10628820, 10800000, 10935000, 11059200, 11197440, 11250000, 11337408, 11390625, 11520000, 4343 11664000, 11718750, 11796480, 11809800, 11943936, 12000000, 12150000, 12288000, 12301875, 4344 12441600, 12500000, 12582912, 12597120, 12656250, 12754584, 12800000, 12960000, 13107200, 4345 13122000, 13271040, 13286025, 13436928, 13500000, 13668750, 13824000, 13996800, 14062500, 4346 14155776, 14171760, 14400000, 14580000, 14745600, 14762250, 14929920, 15000000, 15116544, 4347 15187500, 15360000, 15552000, 15625000, 15728640, 15746400, 15925248, 15943230, 16000000, 4348 16200000, 16384000, 16402500, 16588800, 16777216, 16796160, 16875000, 17006112, 17280000, 4349 17496000, 17578125, 17694720, 17714700, 17915904, 18000000, 18225000, 18432000, 18662400, 4350 18750000, 18874368, 18895680, 18984375, 19131876, 19200000, 19440000, 19531250, 19660800, 4351 19683000, 19906560, 20000000, 20155392, 20250000, 20480000, 20503125, 20736000, 20971520, 4352 20995200, 21093750, 21233664, 21257640, 21600000, 21870000, 22118400, 22143375, 22394880, 4353 22500000, 22674816, 22781250, 23040000, 23328000, 23437500, 23592960, 23619600, 23887872, 4354 23914845, 24000000, 24300000, 24576000, 24603750, 24883200, 25000000, 25165824, 25194240, 4355 25312500, 25509168, 25600000, 25920000, 26214400, 26244000, 26542080, 26572050, 26873856, 4356 27000000, 27337500, 27648000, 27993600, 28125000, 28311552, 28343520, 28800000, 29160000, 4357 29296875, 29491200, 29524500, 29859840, 30000000, 30233088, 30375000, 30720000, 31104000, 4358 31250000, 31457280, 31492800, 31640625, 31850496, 31886460, 32000000, 32400000, 32768000, 4359 32805000, 33177600, 33554432, 33592320, 33750000, 34012224, 34171875, 34560000, 34992000, 4360 35156250, 35389440, 35429400, 35831808, 36000000, 36450000, 36864000, 36905625, 37324800, 4361 37500000, 37748736, 37791360, 37968750, 38263752, 38400000, 38880000, 39062500, 39321600, 4362 39366000, 39813120, 39858075, 40000000, 40310784, 40500000, 40960000, 41006250, 41472000, 4363 41943040, 41990400, 42187500, 42467328, 42515280, 43200000, 43740000, 44236800, 44286750, 4364 44789760, 45000000, 45349632, 45562500, 46080000, 46656000, 46875000, 47185920, 47239200, 4365 47775744, 47829690, 48000000, 48600000, 48828125, 49152000, 49207500, 49766400, 50000000, 4366 50331648, 50388480, 50625000, 51018336, 51200000, 51840000, 52428800, 52488000, 52734375, 4367 53084160, 53144100, 53747712, 54000000, 54675000, 55296000, 55987200, 56250000, 56623104, 4368 56687040, 56953125, 57600000, 58320000, 58593750, 58982400, 59049000, 59719680, 60000000, 4369 60466176, 60750000, 61440000, 61509375, 62208000, 62500000, 62914560, 62985600, 63281250, 4370 63700992, 63772920, 64000000, 64800000, 65536000, 65610000, 66355200, 66430125, 67108864, 4371 67184640, 67500000, 68024448, 68343750, 69120000, 69984000, 70312500, 70778880, 70858800, 4372 71663616, 72000000, 72900000, 73728000, 73811250, 74649600, 75000000, 75497472, 75582720, 4373 75937500, 76527504, 76800000, 77760000, 78125000, 78643200, 78732000, 79626240, 79716150, 4374 80000000, 80621568, 81000000, 81920000, 82012500, 82944000, 83886080, 83980800, 84375000, 4375 84934656, 85030560, 86400000, 87480000, 87890625, 88473600, 88573500, 89579520, 90000000, 4376 90699264, 91125000, 92160000, 93312000, 93750000, 94371840, 94478400, 94921875, 95551488, 4377 95659380, 96000000, 97200000, 97656250, 98304000, 98415000, 99532800, 100000000, 4378 100663296, 100776960, 101250000, 102036672, 102400000, 102515625, 103680000, 104857600, 4379 104976000, 105468750, 106168320, 106288200, 107495424, 108000000, 109350000, 110592000, 4380 110716875, 111974400, 112500000, 113246208, 113374080, 113906250, 115200000, 116640000, 4381 117187500, 117964800, 118098000, 119439360, 119574225, 120000000, 120932352, 121500000, 4382 122880000, 123018750, 124416000, 125000000, 125829120, 125971200, 126562500, 127401984, 4383 127545840, 128000000, 129600000, 131072000, 131220000, 132710400, 132860250, 134217728, 4384 134369280, 135000000, 136048896, 136687500, 138240000, 139968000, 140625000, 141557760, 4385 141717600, 143327232, 144000000, 145800000, 146484375, 147456000, 147622500, 149299200, 4386 150000000, 150994944, 151165440, 151875000, 153055008, 153600000, 155520000, 156250000, 4387 157286400, 157464000, 158203125, 159252480, 159432300, 160000000, 161243136, 162000000, 4388 163840000, 164025000, 165888000, 167772160, 167961600, 168750000, 169869312, 170061120, 4389 170859375, 172800000, 174960000, 175781250, 176947200, 177147000, 179159040, 180000000, 4390 181398528, 182250000, 184320000, 184528125, 186624000, 187500000, 188743680, 188956800, 4391 189843750, 191102976, 191318760, 192000000, 194400000, 195312500, 196608000, 196830000, 4392 199065600, 199290375, 200000000, 201326592, 201553920, 202500000, 204073344, 204800000, 4393 205031250, 207360000, 209715200, 209952000, 210937500, 212336640, 212576400, 214990848, 4394 216000000, 218700000, 221184000, 221433750, 223948800, 225000000, 226492416, 226748160, 4395 227812500, 230400000, 233280000, 234375000, 235929600, 236196000, 238878720, 239148450, 4396 240000000, 241864704, 243000000, 244140625, 245760000, 246037500, 248832000, 250000000, 4397 251658240, 251942400, 253125000, 254803968, 255091680, 256000000, 259200000, 262144000, 4398 262440000, 263671875, 265420800, 265720500, 268435456, 268738560, 270000000, 272097792, 4399 273375000, 276480000, 279936000, 281250000, 283115520, 283435200, 284765625, 286654464, 4400 288000000, 291600000, 292968750, 294912000, 295245000, 298598400, 300000000, 301989888, 4401 302330880, 303750000, 306110016, 307200000, 307546875, 311040000, 312500000, 314572800, 4402 314928000, 316406250, 318504960, 318864600, 320000000, 322486272, 324000000, 327680000, 4403 328050000, 331776000, 332150625, 335544320, 335923200, 337500000, 339738624, 340122240, 4404 341718750, 345600000, 349920000, 351562500, 353894400, 354294000, 358318080, 360000000, 4405 362797056, 364500000, 368640000, 369056250, 373248000, 375000000, 377487360, 377913600, 4406 379687500, 382205952, 382637520, 384000000, 388800000, 390625000, 393216000, 393660000, 4407 398131200, 398580750, 400000000, 402653184, 403107840, 405000000, 408146688, 409600000, 4408 410062500, 414720000, 419430400, 419904000, 421875000, 424673280, 425152800, 429981696, 4409 432000000, 437400000, 439453125, 442368000, 442867500, 447897600, 450000000, 452984832, 4410 453496320, 455625000, 460800000, 466560000, 468750000, 471859200, 472392000, 474609375, 4411 477757440, 478296900, 480000000, 483729408, 486000000, 488281250, 491520000, 492075000, 4412 497664000, 500000000, 503316480, 503884800, 506250000, 509607936, 510183360, 512000000, 4413 512578125, 518400000, 524288000, 524880000, 527343750, 530841600, 531441000, 536870912, 4414 537477120, 540000000, 544195584, 546750000, 552960000, 553584375, 559872000, 562500000, 4415 566231040, 566870400, 569531250, 573308928, 576000000, 583200000, 585937500, 589824000, 4416 590490000, 597196800, 597871125, 600000000, 603979776, 604661760, 607500000, 612220032, 4417 614400000, 615093750, 622080000, 625000000, 629145600, 629856000, 632812500, 637009920, 4418 637729200, 640000000, 644972544, 648000000, 655360000, 656100000, 663552000, 664301250, 4419 671088640, 671846400, 675000000, 679477248, 680244480, 683437500, 691200000, 699840000, 4420 703125000, 707788800, 708588000, 716636160, 720000000, 725594112, 729000000, 732421875, 4421 737280000, 738112500, 746496000, 750000000, 754974720, 755827200, 759375000, 764411904, 4422 765275040, 768000000, 777600000, 781250000, 786432000, 787320000, 791015625, 796262400, 4423 797161500, 800000000, 805306368, 806215680, 810000000, 816293376, 819200000, 820125000, 4424 829440000, 838860800, 839808000, 843750000, 849346560, 850305600, 854296875, 859963392, 4425 864000000, 874800000, 878906250, 884736000, 885735000, 895795200, 900000000, 905969664, 4426 906992640, 911250000, 921600000, 922640625, 933120000, 937500000, 943718400, 944784000, 4427 949218750, 955514880, 956593800, 960000000, 967458816, 972000000, 976562500, 983040000, 4428 984150000, 995328000, 996451875, 1000000000, 1006632960, 1007769600, 1012500000, 4429 1019215872, 1020366720, 1024000000, 1025156250, 1036800000, 1048576000, 1049760000, 4430 1054687500, 1061683200, 1062882000, 1073741824, 1074954240, 1080000000, 1088391168, 4431 1093500000, 1105920000, 1107168750, 1119744000, 1125000000, 1132462080, 1133740800, 4432 1139062500, 1146617856, 1152000000, 1166400000, 1171875000, 1179648000, 1180980000, 4433 1194393600, 1195742250, 1200000000, 1207959552, 1209323520, 1215000000, 1220703125, 4434 1224440064, 1228800000, 1230187500, 1244160000, 1250000000, 1258291200, 1259712000, 4435 1265625000, 1274019840, 1275458400, 1280000000, 1289945088, 1296000000, 1310720000, 4436 1312200000, 1318359375, 1327104000, 1328602500, 1342177280, 1343692800, 1350000000, 4437 1358954496, 1360488960, 1366875000, 1382400000, 1399680000, 1406250000, 1415577600, 4438 1417176000, 1423828125, 1433272320, 1440000000, 1451188224, 1458000000, 1464843750, 4439 1474560000, 1476225000, 1492992000, 1500000000, 1509949440, 1511654400, 1518750000, 4440 1528823808, 1530550080, 1536000000, 1537734375, 1555200000, 1562500000, 1572864000, 4441 1574640000, 1582031250, 1592524800, 1594323000, 1600000000, 1610612736, 1612431360, 4442 1620000000, 1632586752, 1638400000, 1640250000, 1658880000, 1660753125, 1677721600, 4443 1679616000, 1687500000, 1698693120, 1700611200, 1708593750, 1719926784, 1728000000, 4444 1749600000, 1757812500, 1769472000, 1771470000, 1791590400, 1800000000, 1811939328, 4445 1813985280, 1822500000, 1843200000, 1845281250, 1866240000, 1875000000, 1887436800, 4446 1889568000, 1898437500, 1911029760, 1913187600, 1920000000, 1934917632, 1944000000, 4447 1953125000, 1966080000, 1968300000, 1990656000, 1992903750, 2000000000, 2013265920, 4448 2015539200, 2025000000, 2038431744, 2040733440, 2048000000, 2050312500, 2073600000, 4449 2097152000, 2099520000, 2109375000, 2123366400, 2125764000 4450 }; 4451 4452 } 4453 4454 int cv::getOptimalDFTSize( int size0 ) 4455 { 4456 int a = 0, b = sizeof(optimalDFTSizeTab)/sizeof(optimalDFTSizeTab[0]) - 1; 4457 if( (unsigned)size0 >= (unsigned)optimalDFTSizeTab[b] ) 4458 return -1; 4459 4460 while( a < b ) 4461 { 4462 int c = (a + b) >> 1; 4463 if( size0 <= optimalDFTSizeTab[c] ) 4464 b = c; 4465 else 4466 a = c+1; 4467 } 4468 4469 return optimalDFTSizeTab[b]; 4470 } 4471 4472 CV_IMPL void 4473 cvDFT( const CvArr* srcarr, CvArr* dstarr, int flags, int nonzero_rows ) 4474 { 4475 cv::Mat src = cv::cvarrToMat(srcarr), dst0 = cv::cvarrToMat(dstarr), dst = dst0; 4476 int _flags = ((flags & CV_DXT_INVERSE) ? cv::DFT_INVERSE : 0) | 4477 ((flags & CV_DXT_SCALE) ? cv::DFT_SCALE : 0) | 4478 ((flags & CV_DXT_ROWS) ? cv::DFT_ROWS : 0); 4479 4480 CV_Assert( src.size == dst.size ); 4481 4482 if( src.type() != dst.type() ) 4483 { 4484 if( dst.channels() == 2 ) 4485 _flags |= cv::DFT_COMPLEX_OUTPUT; 4486 else 4487 _flags |= cv::DFT_REAL_OUTPUT; 4488 } 4489 4490 cv::dft( src, dst, _flags, nonzero_rows ); 4491 CV_Assert( dst.data == dst0.data ); // otherwise it means that the destination size or type was incorrect 4492 } 4493 4494 4495 CV_IMPL void 4496 cvMulSpectrums( const CvArr* srcAarr, const CvArr* srcBarr, 4497 CvArr* dstarr, int flags ) 4498 { 4499 cv::Mat srcA = cv::cvarrToMat(srcAarr), 4500 srcB = cv::cvarrToMat(srcBarr), 4501 dst = cv::cvarrToMat(dstarr); 4502 CV_Assert( srcA.size == dst.size && srcA.type() == dst.type() ); 4503 4504 cv::mulSpectrums(srcA, srcB, dst, 4505 (flags & CV_DXT_ROWS) ? cv::DFT_ROWS : 0, 4506 (flags & CV_DXT_MUL_CONJ) != 0 ); 4507 } 4508 4509 4510 CV_IMPL void 4511 cvDCT( const CvArr* srcarr, CvArr* dstarr, int flags ) 4512 { 4513 cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); 4514 CV_Assert( src.size == dst.size && src.type() == dst.type() ); 4515 int _flags = ((flags & CV_DXT_INVERSE) ? cv::DCT_INVERSE : 0) | 4516 ((flags & CV_DXT_ROWS) ? cv::DCT_ROWS : 0); 4517 cv::dct( src, dst, _flags ); 4518 } 4519 4520 4521 CV_IMPL int 4522 cvGetOptimalDFTSize( int size0 ) 4523 { 4524 return cv::getOptimalDFTSize(size0); 4525 } 4526 4527 /* End of file. */
既然修改源码不是好方法,那么只能靠我们自己了!大约有两个方向:一是在OpenCV的基础上自己写一个傅里叶相关的函数(使傅里叶函数变成一个系数卷积核),该函数理应配合像素遍历、扩充图像边界(以便于卷积)、计算幅值、通道分离、通道混合这些函数同时使用。二是在C/C++与windows系统函数的基础上写相关的函数(其工程量很大,几乎等于从图像的存储结构开始搭建图像处理的所需框架)。那么,除此之外还有什么更好的方法吗?据说,可以使用MFC或QT来实现图像处理。然而,这些工作都是比较耗时的,不利于大家学习“图像处理与分析”的核心思想。不可否认,上述提到的方法是有益于大家的编程能力的提升,因此综合各方面考虑之下。博主本篇文章中编写的代码,只注重性质的侧面演示,不注重傅里叶函数的代码实现。关于这些函数的代码实现,博主将会另开一个系列的随笔较为详细的介绍。
【1】傅里叶变换频谱:使用 dft() 及其相关函数,展示频谱。在实验过程中发现,可以使用二值化的方法使频谱的特性凸显出来。代码如下:
1 #pragma once 2 #include "opencv2/core.hpp" 3 #include "opencv2/imgproc.hpp" 4 #include "opencv2/imgcodecs.hpp" 5 #include "opencv2/highgui.hpp" 6 #include <iostream> 7 using namespace cv; 8 #define GRAY_THRESH 10 9 void binar(Mat magImg) 10 { 11 threshold(magImg, magImg, GRAY_THRESH, 255, THRESH_BINARY); 12 imshow("spectrumedd magnitude", magImg); 13 } 14 15 void translation(Mat magI, Mat I, Mat complexI) 16 { 17 normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a 18 // viewable image form (float between values 0 and 1). 19 imshow("spectrumed magnitude", magI); 20 21 // crop the spectrum, if it has an odd number of rows or columns 22 magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); 23 // rearrange the quadrants of Fourier image so that the origin is at the image center 24 int cx = magI.cols / 2; 25 int cy = magI.rows / 2; 26 Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant 27 Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right 28 Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left 29 Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right 30 Mat tmp; // swap quadrants (Top-Left with Bottom-Right) 31 q0.copyTo(tmp); 32 q3.copyTo(q0); 33 tmp.copyTo(q3); 34 q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left) 35 q2.copyTo(q1); 36 tmp.copyTo(q2); 37 38 imshow("Input Image", I); // Show the result 39 imshow("spectrum magnitude", magI); 40 41 // 使用IFFT进行反变换,得到时域图像 42 Mat ifft; 43 idft(complexI, ifft, DFT_REAL_OUTPUT | DFT_SCALE); 44 normalize(ifft, ifft, 0, 1, NORM_MINMAX); 45 imshow("idft", ifft); 46 }
1 #include "Binarization.h" 2 #include <iostream> 3 4 using namespace std; 5 6 static void help(char** argv) 7 { 8 cout << endl 9 << "This program demonstrated the use of the discrete Fourier transform (DFT). " << endl 10 << "The dft of an image is taken and it's power spectrum is displayed." << endl << endl 11 << "Usage:" << endl 12 << argv[0] << " [image_name -- default lena.jpg]" << endl << endl; 13 } 14 int main(int argc, char** argv) 15 { 16 help(argv); 17 const char* filename = argc >= 2 ? argv[1] : "1.png"; 18 Mat I = imread(samples::findFile(filename), IMREAD_GRAYSCALE); 19 if (I.empty()) { 20 cout << "Error opening image" << endl; 21 return EXIT_FAILURE; 22 } 23 Mat padded; //expand input image to optimal size 24 int m = getOptimalDFTSize(I.rows); 25 int n = getOptimalDFTSize(I.cols); // on the border add zero values 26 copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0)); 27 Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) }; 28 Mat complexI; 29 merge(planes, 2, complexI); // Add to the expanded another plane with zeros 30 dft(complexI, complexI); // this way the result may fit in the source matrix 31 // compute the magnitude and switch to logarithmic scale 32 // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) 33 split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) 34 magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude 35 Mat magI = planes[0]; 36 37 // 进行对数尺度缩放 38 magI += Scalar::all(1); // switch to logarithmic scale 39 log(magI, magI); 40 41 Mat bimg=magI.clone(); // 深拷贝,修改新对象,旧对象不变 42 43 normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a 44 // viewable image form (float between values 0 and 1) 45 imshow("spectrumed magnitude", magI); 46 //转为二值图像 47 binar(bimg); 48 49 // translation(magI, I, complexI); 50 51 waitKey(); 52 destroyAllWindows(); 53 return EXIT_SUCCESS; 54 }
运行示例:(注:二值化部分,博主为了频谱图特征凸显出来,使用的像素灰度阈值是10。)
这样,可以清晰地看见图像的大部分信息都集中在四个角。原因是:对于一幅图像,图像中灰度变化比较缓慢的区域可以用较低频率的正弦信号近似,而灰度变化比较大的边缘地带则需要用高频正弦信号近似。一副图像中大部分都是灰度变化缓慢的区域,只有小部分是边缘,因此,其变换域的图像,能量主要集中在低频部分(对应幅值较高),只有小部分能量集中在高频部分(对应的幅值较低)。
【2】平移性:代码如下。
1 #pragma once 2 #include "opencv2/core.hpp" 3 #include "opencv2/imgproc.hpp" 4 #include "opencv2/imgcodecs.hpp" 5 #include "opencv2/highgui.hpp" 6 #include <iostream> 7 using namespace cv; 8 using namespace std; 9 #define GRAY_THRESH 10 10 11 void help(char* argv) 12 { 13 cout << endl 14 << "This program demonstrated the use of the discrete Fourier transform (DFT). " << endl 15 << "The dft of an image is taken and it's power spectrum is displayed." << endl << endl 16 << "Usage:" << endl 17 << argv[0] << " [image_name -- default lena.jpg]" << endl << endl; 18 } 19 20 Mat Predft(Mat I, Mat complexI) 21 { 22 Mat padded; //expand input image to optimal size 23 int m = getOptimalDFTSize(I.rows); 24 int n = getOptimalDFTSize(I.cols); // on the border add zero values 25 copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0)); 26 Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) }; 27 28 merge(planes, 2, complexI); // Add to the expanded another plane with zeros 29 dft(complexI, complexI); // this way the result may fit in the source matrix 30 // compute the magnitude and switch to logarithmic scale 31 // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) 32 split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) 33 magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude 34 Mat magI = planes[0]; 35 36 // 进行对数尺度缩放 37 magI += Scalar::all(1); // switch to logarithmic scale 38 log(magI, magI); 39 return magI; 40 } 41 42 void binar(Mat magImg) 43 { 44 threshold(magImg, magImg, GRAY_THRESH, 255, THRESH_BINARY); 45 imshow("spectrumedd magnitude", magImg); 46 } 47 48 void translation(Mat magI, Mat I, Mat complexI) 49 { 50 normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a 51 // viewable image form (float between values 0 and 1). 52 // imshow("spectrumed magnitude", magI); 53 54 // crop the spectrum, if it has an odd number of rows or columns 55 magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); 56 // rearrange the quadrants of Fourier image so that the origin is at the image center 57 int cx = magI.cols / 2; 58 int cy = magI.rows / 2; 59 Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant 60 Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right 61 Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left 62 Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right 63 Mat tmp; // swap quadrants (Top-Left with Bottom-Right) 64 q0.copyTo(tmp); 65 q3.copyTo(q0); 66 tmp.copyTo(q3); 67 q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left) 68 q2.copyTo(q1); 69 tmp.copyTo(q2); 70 71 //imshow("Input Image", I); // Show the result 72 //imshow("spectrum magnitude", magI); 73 } 74 75 void idft(Mat complexI) 76 { 77 // 使用IFFT进行反变换,得到时域图像 78 Mat ifft; 79 idft(complexI, ifft, DFT_REAL_OUTPUT | DFT_SCALE); 80 normalize(ifft, ifft, 0, 1, NORM_MINMAX); 81 imshow("idft", ifft); 82 }
1 #include "Binarization.h" 2 #include <iostream> 3 4 using namespace std; 5 6 int main(int argc, char** argv) 7 { 8 char fn[] = "1.png"; 9 char fn1[] = "8.png"; 10 help(fn); 11 help(fn1); 12 Mat complexI; 13 Mat complexI1; 14 15 Mat I = imread(samples::findFile(fn), IMREAD_GRAYSCALE); 16 Mat I1 = imread(samples::findFile(fn1), IMREAD_GRAYSCALE); 17 18 if (I.empty() && I1.empty()) { 19 cout << "Error opening image" << endl; 20 return EXIT_FAILURE; 21 } 22 23 Mat magI = Predft(I, complexI); 24 //Mat magI1 = Predft(I1, complexI1); 25 26 threshold(magI, magI, GRAY_THRESH, 255, THRESH_BINARY); 27 //threshold(magI1, magI1, GRAY_THRESH, 255, THRESH_BINARY); 28 imshow("spectrumed magnitude", magI); 29 translation(magI, I, complexI); 30 // imshow("Input Image", I); // Show the result 31 imshow("spectrum magnitude", magI); 32 //translation(magI1, I1, complexI1); 33 //imshow("Input Image1", I1); // Show the result 34 //imshow("spectrum magnitude1", magI1); 35 36 waitKey(); 37 destroyAllWindows(); 38 return EXIT_SUCCESS; 39 }
运行示例:
【3】旋转不变性:代码如下(头文件与上述相同;【注】旋转过程可能把图片放大了,旋转过程也是颇为有趣的)。
1 #include "Binarization.h" 2 #include <iostream> 3 4 using namespace std; 5 6 int main(int argc, char** argv) 7 { 8 char fn[] = "7.png"; 9 char fn1[] = "8.png"; 10 help(fn); 11 help(fn1); 12 Mat complexI; 13 Mat complexI1; 14 15 Mat I = imread(samples::findFile(fn), IMREAD_GRAYSCALE); 16 Mat I1 = imread(samples::findFile(fn1), IMREAD_GRAYSCALE); 17 18 if (I.empty() && I1.empty()) { 19 cout << "Error opening image" << endl; 20 return EXIT_FAILURE; 21 } 22 23 Mat magI = Predft(I, complexI); 24 Mat magI1 = Predft(I1, complexI1); 25 26 threshold(magI, magI, GRAY_THRESH, 255, THRESH_BINARY); 27 threshold(magI1, magI1, GRAY_THRESH, 255, THRESH_BINARY); 28 // imshow("spectrumed magnitude", magI); 29 translation(magI, I, complexI); 30 imshow("Input Image", I); // Show the result 31 imshow("spectrum magnitude", magI); 32 translation(magI1, I1, complexI1); 33 imshow("Input Image1", I1); // Show the result 34 imshow("spectrum magnitude1", magI1); 35 36 waitKey(); 37 destroyAllWindows(); 38 return EXIT_SUCCESS; 39 }
运行实例:
【4】比例性:代码同3。运行示例如下:
【5】中心化:中心化指在平移后频谱图中,图像的大部分信息集中在中心的位置。可以通过乘上一个(-1)x+y因子使频域中心从原点移到N×N方阵的中心。为了更好地演示中心化这个性质,有必要先介绍傅里叶的逆变换。代码如下:
1 #pragma once 2 #include "opencv2/core.hpp" 3 #include "opencv2/imgproc.hpp" 4 #include "opencv2/imgcodecs.hpp" 5 #include "opencv2/highgui.hpp" 6 #include <iostream> 7 using namespace cv; 8 using namespace std; 9 #define GRAY_THRESH 10 10 11 void help(char* argv) 12 { 13 cout << endl 14 << "This program demonstrated the use of the discrete Fourier transform (DFT). " << endl 15 << "The dft of an image is taken and it's power spectrum is displayed." << endl << endl 16 << "Usage:" << endl 17 << argv[0] << " [image_name -- default lena.jpg]" << endl << endl; 18 } 19 20 void idfft(Mat complexI, int col, int row) 21 { 22 // 使用IFFT进行反变换,得到时域图像 23 Mat ifft; 24 idft(complexI, ifft, DFT_REAL_OUTPUT | DFT_SCALE); 25 normalize(ifft, ifft, 0, 1, NORM_MINMAX); 26 imshow("idft", ifft); 27 Mat imageROI; 28 // 方法1 29 imageROI = ifft(Rect(0, 0, col, row)).clone(); 30 // cout << imageROI << endl; 31 imshow("idfft", imageROI); 32 } 33 34 Mat Predft(Mat I, Mat complexI, bool bdift = 0) 35 { 36 Mat padded; //expand input image to optimal size 37 int m = getOptimalDFTSize(I.rows); 38 int n = getOptimalDFTSize(I.cols); // on the border add zero values 39 40 //cout << m << endl; // 576 41 //cout << n << endl; // 576 42 //cout << m - I.rows << endl; // 6 43 //cout << n - I.cols << endl; // 23 44 45 copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0)); 46 Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) }; 47 48 merge(planes, 2, complexI); // Add to the expanded another plane with zeros 49 dft(complexI, complexI); // this way the result may fit in the source matrix 50 // compute the magnitude and switch to logarithmic scale 51 // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) 52 split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) 53 magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude 54 Mat magI = planes[0]; 55 56 // 进行对数尺度缩放 57 magI += Scalar::all(1); // switch to logarithmic scale 58 log(magI, magI); 59 60 if (bdift) // 逆变换 61 { 62 // 定义一个Mat类型并给其设定ROI区域 63 // Mat imageROI; 64 // 方法1 65 // imageROI = complexI(Rect(0, 0, I.cols, I.rows)).clone(); 66 // dft(imageROI, imageROI, DFT_COMPLEX_OUTPUT); 67 // dft(imageROI, imageROI, DFT_INVERSE); 68 // normalize(imageROI, imageROI, 0, 1, NORM_MINMAX); 69 // imshow("dft_real_output", imageROI); 70 idfft(complexI, I.cols, I.rows); 71 } 72 73 return magI; 74 } 75 76 void binar(Mat magImg) 77 { 78 threshold(magImg, magImg, GRAY_THRESH, 255, THRESH_BINARY); 79 imshow("spectrumedd magnitude", magImg); 80 } 81 82 void translation(Mat magI, Mat I, Mat complexI) 83 { 84 normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a 85 // viewable image form (float between values 0 and 1). 86 // imshow("spectrumed magnitude", magI); 87 88 // crop the spectrum, if it has an odd number of rows or columns 89 magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); 90 // rearrange the quadrants of Fourier image so that the origin is at the image center 91 int cx = magI.cols / 2; 92 int cy = magI.rows / 2; 93 Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant 94 Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right 95 Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left 96 Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right 97 Mat tmp; // swap quadrants (Top-Left with Bottom-Right) 98 q0.copyTo(tmp); 99 q3.copyTo(q0); 100 tmp.copyTo(q3); 101 q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left) 102 q2.copyTo(q1); 103 tmp.copyTo(q2); 104 105 //imshow("Input Image", I); // Show the result 106 //imshow("spectrum magnitude", magI); 107 } 108 109 bool Scaling() 110 { 111 char fn[] = "7.png"; 112 char fn1[] = "9.png"; 113 cout << "输入需要比较的两幅图像:" << endl; 114 cin >> fn >> fn1; 115 116 help(fn); 117 help(fn1); 118 Mat complexI; 119 Mat complexI1; 120 121 Mat I = imread(samples::findFile(fn), IMREAD_GRAYSCALE); 122 Mat I1 = imread(samples::findFile(fn1), IMREAD_GRAYSCALE); 123 124 if (I.empty() && I1.empty()) { 125 cout << "Error opening image" << endl; 126 return false; 127 } 128 129 Mat magI = Predft(I, complexI); 130 Mat magI1 = Predft(I1, complexI1); 131 132 threshold(magI, magI, GRAY_THRESH, 255, THRESH_BINARY); 133 threshold(magI1, magI1, GRAY_THRESH, 255, THRESH_BINARY); 134 // imshow("spectrumed magnitude", magI); 135 translation(magI, I, complexI); 136 imshow("Input Image", I); // Show the result 137 imshow("spectrum magnitude", magI); 138 translation(magI1, I1, complexI1); 139 imshow("Input Image1", I1); // Show the result 140 imshow("spectrum magnitude1", magI1); 141 return true; 142 }
1 #include "Binarization.h" 2 #include <iostream> 3 4 using namespace std; 5 6 int main(int argc, char** argv) 7 { 8 char fn[] = "1.png"; 9 help(fn); 10 Mat complexI; 11 Mat I = imread(samples::findFile(fn), IMREAD_GRAYSCALE); 12 // cout << I << endl; 输出较慢 13 Mat magI = Predft(I, complexI, 1); // dft, 当是1时输出逆变换 14 threshold(magI, magI, GRAY_THRESH, 255, THRESH_BINARY); // 二值化 15 translation(magI, I, complexI); // 输出 16 imshow("Input Image", I); // Show the result 17 imshow("spectrum magnitude", magI); // 频谱图 18 // if (!Scaling()) 19 // cout << "输入有误!" << endl; 20 waitKey(); 21 destroyAllWindows(); 22 return EXIT_SUCCESS; 23 }
运行示例:(注:因为在进行dft的过程中增加了图像矩阵的维度,所以idft图像存在黑边。因此博主做了ROI区域化的处理,得到idfft图。)显然尽管频域中心发生了位移,图像并未发生明显的改变。
除此之外,本文还做了一些傅里叶变换在图像处理中的简单应用。傅里叶变换可以对图像的频谱进行各种各样的处理,如滤波、降噪、增强等。
参考文献
[1] 张弘.数字图像处理与分析[M].北京,机械工业出版社.2013.3(2017.6重印).
--------------------------------------------------------------continue-------------------------------------------