C++实现二维离散傅里叶变换

2023-05-16

在上一篇文章《C++实现一维离散傅里叶变换》中,我们介绍了一维信号傅立叶变换的公式和C++实现,并阐述了频域幅值的意义。

一维傅立叶变换只适用于一维信号,例如音频数据、心脑电图等。

在图像处理中,图像信号具有高度和宽度两个属性,属于二维空间信号。将图像信号从空间域转换到频域时,需使用二维离散傅立叶变换。因此,需要将傅立叶变换从一维推广至二维。

二维连续傅立叶变换公式如下:

经过离散化后,上述公式变为:

,其中u=0,1,2,…,M-1,v=0,1,2,…,N-1。              (式1-1)

相应地,其逆变换为:

对式1-1稍作变换,可得:

其中,刚好是一维傅立叶变换的离散形式。故二维傅立叶变换可理解为先对图像的每一行进行一维傅立叶变换,变换的结果构成一个新的矩阵,再对新矩阵的每一列进行一维傅立叶变换,这样经过两次变换的结果就是二维傅立叶变换的最终结果。

也就是说,二维傅里叶变换相当于先按行变换,再按列变换(也可以先按列变换,再按行变换)。最终生成的频域数据,就是由两个方向的频率强度信息叠加而成。

我们可以用伪代码来实现上述逻辑。假设一维傅里叶变换函数为dft1(vec),二维信号高度为h,宽度为w,那么伪代码可写成如下形式:
for (int i=0; i<h; i++)

    dft1(row[i]);

for (int i=0; i<w; i++)

    dft1(column[i]);


在本文中,我们暂不采用上述伪代码思路。我们直接按式1-1来进行编程实现:

其中,e-i2π(ux/M+vy/N)可转化为三角函数cos(-2π(ux/M+vy/N))+isin(-2π(ux/M+vy/N)),i为虚数单位。转化成三角函数形式,有利于计算机编程实现。只需要采用两个for循环,就可求出单个F(u,v)值,外面再嵌套两个for循环,即可求出所有F(u,v)值。

故得到有利于编程实现的离散傅里叶变换公式如下:


由于涉及复数运算,需要先定义一个复数类,并实现复数运算。

在上一篇文章《C++实现一维离散傅里叶变换》中,我们已经实现了一个复数类ComplexNumber。直接引用它即可。

(注:编译环境是VS2013,使用MFC对话框模板)

二维离散傅里叶变换的头文件如下:

Dft2.h
#pragma once
#include "ComplexNumber.h"
 
#define      MAX_MATRIX_SIZE                4194304             // 2048 * 2048
#define      PI                                           3.141592653
 
class CDft2
{
public:
    CDft2(void);
    ~CDft2(void);
 
public:
    bool dft2(double IN const matrix[], int IN const width, int IN const height);       // 二维离散傅里叶变换
    bool idft2(LPVOID OUT *pMatrix, int OUT *width, int OUT *height);                 // 二维离散傅里叶逆变换
 
    void generate_spectrum();                   // 对变换结果求模,生成频谱/幅度谱
    void normalize_spectrum();                  // 对频谱进行归一化操作
 
    bool has_dft2_matrix();                         // 是否已存有变换结果
    bool is_shifted_to_center();                  // 是否已将频谱原点平移到图像中心
 
    void clear_dft2_matrix();                       // 清除已有的变换结果
    void print_matrix();                                // 打印变换结果
    void print_spectrum();                           // 打印频谱
    void shift_spectrum_to_center();          // 将频谱原点平移到图像中心
 
public:
    CComplexNumber *m_dft2_matrix;
    double                    *m_spectrum_data;
 
protected:
    bool      m_has_dft_matrix;
    bool      m_is_normalized;
    bool      m_is_spectrum_shifted;
    int         m_dft_matrix_height;
    int         m_dft_matrix_width;
};
由于二维傅里叶变换后得到的矩阵元素数值很大,并且包含实数和虚数。为便于观察分析,需要将变换后的结果进行求模,然后归一化到[0,255],以便保存为频谱图。归一化后,大部分像素灰度较低,在频谱图上接近黑色,肉眼不容易察觉,因此还需要使用log函数对低灰度区域进行增强。另外,由于傅里叶变换本身具有对称性,最终生成的频谱图的四个角也具有对称性,因此,一般在完成归一化后,还有一个把频谱原点平移到频谱图中心的操作。在类CDft2的声明中,对应的求模、归一化和中心平移函数分别为generate_spectrum()、normalize_spectrum()和shift_spectrum_to_center()。
实现文件如下:

Dft2.cpp

#include "StdAfx.h"
#include "Dft2.h"
 
CDft2::CDft2(void)
{
    m_dft2_matrix = NULL;
    m_spectrum_data = NULL;
    m_has_dft_matrix = false;
    m_is_normalized = false;
    m_is_spectrum_shifted = false;
    m_dft_matrix_height = 0;
    m_dft_matrix_width = 0;
}
 
CDft2::~CDft2(void)
{
    if (m_has_dft_matrix && (NULL != m_dft2_matrix) && ((m_dft_matrix_height*m_dft_matrix_width)>0))
        delete[] m_dft2_matrix;
    if (NULL != m_spectrum_data)
        delete[] m_spectrum_data;
}
 
 
bool CDft2::has_dft2_matrix()
{
    return m_has_dft_matrix;
}
bool CDft2::is_shifted_to_center()
{
    return m_is_spectrum_shifted;
}
 
 
void CDft2::clear_dft2_matrix()
{
    if (m_has_dft_matrix && (NULL != m_dft2_matrix) && ((m_dft_matrix_height*m_dft_matrix_width)>0)) {
        delete[] m_dft2_matrix;
        m_has_dft_matrix = false;
        m_dft_matrix_height = 0;
        m_dft_matrix_width = 0;
    }
}
 
 
void CDft2::print_matrix()
{
    char msg[2560] = "11111 ";
 
    if ((!m_has_dft_matrix) || (NULL == m_dft2_matrix) || (m_dft_matrix_height <= 0) || (m_dft_matrix_width <= 0))
        return;
 
    for (int u = 0; u<m_dft_matrix_height; u++) {
        for (int v = 0; v<m_dft_matrix_width; v++) {
            sprintf(msg + 6, "[%d,%d]: %lf + %lfi", u + 1, v + 1, m_dft2_matrix[v + u*m_dft_matrix_width].m_rl, m_dft2_matrix[v + u*m_dft_matrix_width].m_im);
            OutputDebugStringA(msg);
        }
    }
}
 
void CDft2::print_spectrum()
{
    char msg[256] = "11111 ";
 
    if ((!m_has_dft_matrix) || (NULL == m_dft2_matrix) || (m_dft_matrix_height <= 0) || (m_dft_matrix_width <= 0) || (NULL == m_spectrum_data))
        return;
 
    for (int u = 0; u<m_dft_matrix_height; u++) {
        for (int v = 0; v<m_dft_matrix_width; v++) {
            sprintf(msg + 6, "[%d,%d]: %lf", u + 1, v + 1, m_spectrum_data[v + u*m_dft_matrix_width]);
            OutputDebugStringA(msg);
        }
    }
}
 
 
// Fourier transform of 2-dimension matrix
// Param1: the input matrix to be transformed
// Param 2: width of the input matrix
// Param 3: height of the input matrix
bool CDft2::dft2(double IN const matrix[], int IN const width, int IN const height)
{
    if (((width*height) <= 0) || ((width*height)>MAX_MATRIX_SIZE) || (NULL == matrix))
        return false;
 
    // to avoid memory leak, make sure to clear existing data buff before executing the transformation
    clear_dft2_matrix();
 
    m_dft2_matrix = new CComplexNumber[width*height];
    CComplexNumber   cplTemp(0, 0);
    double fixed_factor_for_axisX = (-2 * PI) / height;                   // evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
    double fixed_factor_for_axisY = (-2 * PI) / width;                   // evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
    for (int u = 0; u<height; u++) {
        for (int v = 0; v<width; v++) {
            for (int x = 0; x<height; x++) {
                for (int y = 0; y<width; y++) {
                    double powerX = u * x * fixed_factor_for_axisX;         // evaluate -i2πux/N
                    double powerY = v * y * fixed_factor_for_axisY;         // evaluate -i2πux/N
                    cplTemp.m_rl = matrix[y + x*width] * cos(powerX + powerY);         // evaluate f(x) * e^(-i2πux/N), which is equal to f(x) * (cos(-i2πux/N)+sin(-i2πux/N)i) according to Euler's formula
                    cplTemp.m_im = matrix[y + x*width] * sin(powerX + powerY);
                    m_dft2_matrix[v + u*width] = m_dft2_matrix[v + u*width] + cplTemp;
                }
            }
        }
    }
 
    // now we have the transformed vector, keep the info
    m_has_dft_matrix = true;
    m_dft_matrix_height = height;
    m_dft_matrix_width = width;
    return true;
}
 
 
// Fourier transform of 2-dimension matrix
// Param1: the input matrix to be transformed
// Param 2: width of the input matrix
// Param 3: height of the input matrix
bool CDft2::idft2(LPVOID OUT *pMatrix, int OUT *width, int OUT *height)
{
    char msg[256] = "11111 ";
 
    if ((!m_has_dft_matrix) || (NULL == m_dft2_matrix) || ((m_dft_matrix_height*m_dft_matrix_width) <= 0) || (!width) || (!height))
        return false;
 
    if (*pMatrix)
        delete[] * pMatrix;
    *pMatrix = (LPVOID)new double[m_dft_matrix_height*m_dft_matrix_width];
 
    CComplexNumber   cplTemp(0, 0);
    CComplexNumber   cplResult(0, 0);
    double fixed_factor_for_axisX = (2 * PI) / m_dft_matrix_height;                  // evaluate i2π/N of i2πux/N, and store the value for computing efficiency
    double fixed_factor_for_axisY = (2 * PI) / m_dft_matrix_width;                   // evaluate i2π/N of i2πux/N, and store the value for computing efficiency
    for (int x = 0; x<m_dft_matrix_height; x++) {
        for (int y = 0; y<m_dft_matrix_width; y++) {
            for (int u = 0; u<m_dft_matrix_height; u++) {
                for (int v = 0; v<m_dft_matrix_width; v++) {
                    double powerU = u * x * fixed_factor_for_axisX;         // evaluate i2πux/N
                    double powerV = v * y * fixed_factor_for_axisY;         // evaluate i2πux/N
                    cplTemp.SetValue(cos(powerU + powerV), sin(powerU + powerV));
                    cplResult = cplResult + m_dft2_matrix[v + u*m_dft_matrix_width] * cplTemp;
                }
            }
            ((double*)*pMatrix)[y + x*m_dft_matrix_width] = cplResult.m_rl / (m_dft_matrix_height*m_dft_matrix_width);
            cplResult.SetValue(0, 0);
        }
    }
 
    // now we have the inverse transformed matrix, keep the info
    sprintf(msg + 6, "inverse fourier result: %lX", pMatrix);
    OutputDebugStringA(msg);
    *width = m_dft_matrix_width;
    *height = m_dft_matrix_height;
    return true;
}
 
 
void CDft2::generate_spectrum()
{
    if (m_has_dft_matrix && (NULL != m_dft2_matrix) && ((m_dft_matrix_height*m_dft_matrix_width)>0)) {
        if (NULL != m_spectrum_data) {
            delete[] m_spectrum_data;
            m_is_spectrum_shifted = false;
        }
        m_spectrum_data = new double[m_dft_matrix_height*m_dft_matrix_width];
        for (int u = 0; u<m_dft_matrix_height; u++) {
            for (int v = 0; v<m_dft_matrix_width; v++) {
                double a = m_dft2_matrix[v + u*m_dft_matrix_width].m_rl * m_dft2_matrix[v + u*m_dft_matrix_width].m_rl;
                double b = m_dft2_matrix[v + u*m_dft_matrix_width].m_im * m_dft2_matrix[v + u*m_dft_matrix_width].m_im;
                m_spectrum_data[v + u*m_dft_matrix_width] = sqrt(a + b);
            }
        }
    }
}
 
void CDft2::normalize_spectrum()
{
    char msg[256] = "11111 ";
    if (m_has_dft_matrix && (NULL != m_dft2_matrix) && ((m_dft_matrix_height*m_dft_matrix_width)>0) && ((NULL != m_spectrum_data))) {
        // get max value
        double max = 0;
        for (int u = 0; u<m_dft_matrix_height; u++) {
            for (int v = 0; v<m_dft_matrix_width; v++) {
                if (m_spectrum_data[v + u*m_dft_matrix_width] > max) {
                    max = m_spectrum_data[v + u*m_dft_matrix_width];
                }
            }
        }
 
        // normalize
        if (max <= 0) {
            OutputDebugStringA("11111 Dft2D::NormalizeSpectrum() max value is incorrect! function aborts.");
            return;
        }
        else {
            for (int u = 0; u<m_dft_matrix_height; u++) {
                for (int v = 0; v<m_dft_matrix_width; v++) {
                    m_spectrum_data[v + u*m_dft_matrix_width] = (255 * m_spectrum_data[v + u*m_dft_matrix_width]) / max;
                }
            }
        }
        m_is_normalized = true;
 
        sprintf(msg + 6, "max: %lf", max);
        OutputDebugStringA(msg);
    }
    else
        m_is_normalized = false;
}
 
 
void CDft2::shift_spectrum_to_center()
{
    char msg[256] = "11111 ";
 
    if (m_is_spectrum_shifted)
        return;
    if (m_has_dft_matrix && (NULL != m_dft2_matrix) && ((m_dft_matrix_height*m_dft_matrix_width)>0) && ((NULL != m_spectrum_data))) {
        double *tempData = new double[m_dft_matrix_height*m_dft_matrix_width];
        memcpy(tempData, m_spectrum_data, m_dft_matrix_height*m_dft_matrix_width*sizeof(double));
        //移到中心  
 
        for (int u = 0; u<m_dft_matrix_height; u++) {
            for (int v = 0; v<m_dft_matrix_width; v++) {
                //sprintf(msg+6, "%d, %d, tempData: %lf", u+1, v+1, tempData[v+u*m_nDftMatrixWidth]);
                //OutputDebugStringA(msg);
                if ((u<(m_dft_matrix_height / 2)) && (v<(m_dft_matrix_width / 2))) {
                    m_spectrum_data[v + u*m_dft_matrix_width] =
                        tempData[m_dft_matrix_width / 2 + v + (m_dft_matrix_height / 2 + u)*m_dft_matrix_width];
                }
                else if ((u<(m_dft_matrix_height / 2)) && (v >= (m_dft_matrix_width / 2))) {
                    m_spectrum_data[v + u*m_dft_matrix_width] =
                        tempData[(v - m_dft_matrix_width / 2) + (m_dft_matrix_height / 2 + u)*m_dft_matrix_width];
                }
                else if ((u >= (m_dft_matrix_height / 2)) && (v<(m_dft_matrix_width / 2))) {
                    m_spectrum_data[v + u*m_dft_matrix_width] =
                        tempData[(m_dft_matrix_width / 2 + v) + (u - m_dft_matrix_height / 2)*m_dft_matrix_width];
                }
                else if ((u >= (m_dft_matrix_height / 2)) && (v >= (m_dft_matrix_width / 2))) {
                    m_spectrum_data[v + u*m_dft_matrix_width] =
                        tempData[(v - m_dft_matrix_width / 2) + (u - m_dft_matrix_height / 2)*m_dft_matrix_width];
                }
            }
        }
        m_is_spectrum_shifted = true;
 
        if (tempData)
            delete[] tempData;
    }
}


在CDft2实现文件中,实现二维傅里叶变换的函数dft2()主要代码如下(基本是按照式1-1来实现):

    m_dft2_matrix = new CComplexNumber[width*height];
    CComplexNumber   cplTemp(0, 0);
    double fixed_factor_for_axisX = (-2 * PI) / height;                   // evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
    double fixed_factor_for_axisY = (-2 * PI) / width;                   // evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
    for (int u = 0; u<height; u++) {
        for (int v = 0; v<width; v++) {
            for (int x = 0; x<height; x++) {
                for (int y = 0; y<width; y++) {
                    double powerX = u * x * fixed_factor_for_axisX;         // evaluate -i2πux/N
                    double powerY = v * y * fixed_factor_for_axisY;         // evaluate -i2πux/N
                    cplTemp.m_rl = matrix[y + x*width] * cos(powerX + powerY);         // evaluate f(x) * e^(-i2πux/N), which is equal to f(x) * (cos(-i2πux/N)+sin(-i2πux/N)i) according to Euler's formula
                    cplTemp.m_im = matrix[y + x*width] * sin(powerX + powerY);
                    m_dft2_matrix[v + u*width] = m_dft2_matrix[v + u*width] + cplTemp;
                }
            }
        }
    }
逆变换函数idft2()也主要是按照前面给出的逆变换公式定义来实现。
求模函数generate_spectrum()的实现逻辑:对于复数x = a+bi,其模为m = mod(x) = sqrt(a2+b2),其中sqrt代表根号。

归一化函数normalize_spectrum()的实现逻辑:先遍历矩阵,找到最大值max,然后对于矩阵中的每一个元素matrix[i],执行matrix[i] = 255*(matrix[i]/max),从而归一化到[0,255]。

平移中心函数shift_spectrum_to_center()的实现逻辑:将频谱图平分为4个象限,将1、3象限对换,2、4象限对换。主要通过坐标转换实现。


现在,我们编写并运行一个测试线程,对一个包含三行四列数据的二维信号进行傅里叶变换,以验证上述代码。

DWORD WINAPI test(LPVOID lParam)
{
    char msg[256] = "11111 ";
 
    int width = 4;
    int height = 3;
    double mat[] = { 1, 1, 3, 2, 3, 4, 123, 154, 55, 2, 22, 233 };
 
    // Fourier transform
    CDft2 dft2;
    dft2.dft2(mat, width, height);
    dft2.print_matrix();
 
    dft2.generate_spectrum();
    dft2.normalize_spectrum();
    dft2.print_spectrum();
 
    // inverse Fourier transform
    LPVOID pMat = NULL;
    int iHeight = 0;
    int iWidth = 0;
    dft2.idft2(&pMat, &iWidth, &iHeight);
 
    double *iMat = (double *)pMat;
    if (((iWidth*iHeight)>0) && (NULL != iMat)) {
        for (int x = 0; x<iHeight; x++) {
            for (int y = 0; y<iWidth; y++) {
                sprintf(msg+6, "inverse fourier result %d, %d: %lf, %lf", x+1, y+1, iMat[y+x*iWidth]);
                OutputDebugStringA(msg);
            }
        }
        delete[] iMat;
    }
 
    return 0;
}
在MFC对话框资源中添加一个test按钮,在按钮事件响应函数中添加:

::CreateThread(NULL,0, test, 0, 0, NULL);

然后编译项目。编译成功后,先打开DebugView日志观察工具,再启动生成的exe,点击test按钮,可以在DebugView中看到以下日志输出:


可以看到,逆变换的结果和原始信号完全一致。

使用Matlab的fft2()函数对原始信号进行变换,得到的结果也和上述变换结果一致。

因此我们的实现代码是有效的,输出了正确的变换结果。

当原始信号超过512*512时,本文给出的实现代码执行一次变换大约需要几十秒,这令人难以忍受。

后续我们将介绍基于蝶形分解的快速傅里叶变换,其完成一次512*512原始信号变换只需要几十毫秒。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++实现二维离散傅里叶变换 的相关文章

  • Windows Media Foundation 音视频采集 小记

    写在前面 我是个讲文明的人 不过有的时候实在忍不住了也要吐槽几句 xff1a 1 我真是跟不上时代 xff0c 到现在了还在研究 Windows 应用开发 咳 xff1b 2 DirectShow 是傻X xff01 我只是想要获取 Cam
  • 关于C++中vector和set使用sort方法进行排序

    C 43 43 中vector和set都是非常方便的容器 xff0c sort方法是algorithm头文件里的一个标准函数 xff0c 能进行高效的排序 xff0c 默认是按元素从小到大排序 将sort方法用到vector和set中能实现
  • C#调用C++(opencv)中图片数据传递的问题

    C 43 43 DLL代码 xff1a C 代码 xff1a 课题需要做一个界面 xff0c 因为某些原因不能用emgucv xff0c 需要在C winform中调用opencv的方法 xff0c 用opencv处理图片之后再传回到C p
  • c#调用c++(Opencv)dll的实例

    c 43 43 代码 MYDLL int GetCenterPos uchar imageData int step int widthValue int heightValue int BinaryThreshold int LineBl
  • OpenCV图像锐化/增强

    OpenCV图像锐化 增强 0 综述 1 Laplacian高通滤波算子 2 Laplacian锐化代码实践 3 USM锐化增强算法 4 USM代码实践 0 综述 图像的卷积计算除了可以完成我们前面介绍的模糊去噪 边缘检测等任务外 xff0
  • OpenCV 图像清晰度评价算法(相机自动对焦)

    相机的自动对焦要求相机根据拍摄环境和场景的变化 xff0c 通过相机内部的微型驱动马达 xff0c 自动调节相机镜头和CCD之间的距离 xff0c 保证像平面正好投影到CCD的成像表面上 这时候物体的成像比较清晰 xff0c 图像细节信息丰
  • 图像清晰度评价15种方法对比

    在无参考图像的质量评价中 xff0c 图像的清晰度是衡量图像质量优劣的重要指标 xff0c 它能够较好的与人的主观感受相对应 xff0c 图像的清晰度不高表现出图像的模糊 本文针对无参考图像质量评价应用 xff0c 对目前几种较为常用的 具
  • opencv系列-图像清晰度评价

    opencv系列 图像清晰度评价 1 xff0c 换了opencv3 4 xff0c 用来测试 2 xff0c opencv好评呀 图像清晰度评价算法有很多种 xff0c 在空域中 xff0c 主要思路是考察图像的领域对比度 xff0c 即
  • 一种新的图像清晰度评价函数,数字图像清晰度评价函数的研究与改进

    摘要 xff1a 摘 要 xff1a 通过分析常见的图像清晰度评价函数 xff0c 针对自动对焦系统中图像清晰度评价问题 xff0c 提出了一种基于聚焦窗口的改进梯度评价函数算法 改进后的算法具有计算量小 实时性好 评价曲线单峰性好 灵敏度
  • 11种图像清晰度评价函数

    典型无参考图像清晰度评价 xff08 可用作对焦评价函数 xff09 Tenengrad评价函数 Tenengrad函数是一种由Tenenbaum提出的 xff0c 基于梯度的常用图像清晰度评价函数 特南梯度 在图像处理中 xff0c 一般
  • TouchGFX界面开发 | C++基础

    C 43 43 基础 TouchGFX是一个基于STM32硬件 xff0c 由C 43 43 写成的软件框架 xff0c 所以有必要对C 43 43 基础有一定的了解 一 C 43 43 新特性 C 语言里 xff0c 变量初始化必须在程序
  • 一种新的图像清晰度评价函数

    自动聚焦是机器人视觉 数字视频系统中的关键技术之 是决定图像质量的重要因素 是获取清晰图 像的第1步 聚焦性能取决于调焦评价函数的准确性和有效性 即评价函数必须具有无偏性好 单峰性强和 较好的抗噪性能 图像模糊的本质是高频分量的损失 聚焦图
  • 遍历Opencv中Mat中每个像素的值

    首先 xff0c 在Opencv2中基本上都是用的Mat来表示图像了 xff0c C 43 43 的函数调用中基本上也都是Mat图 xff0c 从根本上说 xff0c 一张图像是一个由数值组成的矩阵 xff0c 矩阵的每一个元素代表一个像素
  • 遍历opencv中的mat像素的几种方法和概念

    今天在看矩形滤波的时候忽然脑子短路 xff0c 把一些概念全弄混了 xff0c 现总结一下 xff0c 以便下次再混的时候可以参考确认下 xff0c 自己的理解 xff0c 有错的地方还请指正 首先 xff0c 在Opencv2中基本上都是
  • C#中的Lock锁深入理解

    lock语句 lock 语句获取给定对象的互斥 lock xff0c 执行语句块 xff0c 然后释放 lock 持有 lock 时 xff0c 持有 lock 的线程可以再次获取并释放 lock 阻止任何其他线程获取 lock 并等待释放
  • C#四种相等性判断方法 equals,referenceEquals

    C 中的ReferenceEquals Equals以及 61 61 C 中有一共有四种相等性判断方法 xff1a Object中定义的三个方法 public static bool ReferenceEquals object objLe
  • C++的Opencv动态库遇到的问题

    1 c 中的位图传入时注意bitmapdata的 stride这个参数 xff0c 步幅 xff0c 图像宽度 通道数 xff0c 必须是整4的倍数貌似 xff0c 待确定 2 某个对象正在在使用的异常 xff0c 用lock锁锁住共享资源
  • C#内存分配概念

    在C 中 xff0c 内存分成5个区 xff0c 他们分别是堆 栈 自由存储区 全局 静态存储区和常量存储区 栈 xff0c 就是那些由编译器在需要的时候分配 xff0c 在不需要的时候自动清楚的变量的存储区 里面的变量通常是局部变量 函数
  • C#中Marshal 类的内存操作的一般功能概述

    Marshal 类的内存操作的一般功能 Marshal类 提供了一个方法集 xff0c 这些方法用于分配非托管内存 复制非托管内存块 将托管类型转换为非托管类型 xff0c 此外还提供了在与非托管代码交互时使用的其他杂项方法 命名空间 Sy
  • C# Marshal的使用,非托管内存中分配内存注意的问题

    IntPtr ptr 61 Marshal AllocHGlobal 704 576 3 如果没有手动释放内存 xff0c 会有内存溢出 xff1b 发生OutOfMemoryException 没有足够的内存继续执行程序时引发的异常 调用

随机推荐

  • Lock锁的问题

    多个线程共用一个锁时 xff0c 同一时间只有一个可获得锁执行 xff0c 其他线程会阻塞进入队列 xff0c 按理解事件如果是多线程的 xff0c 那么每次事件触发的含lock的函数都会将进入队列等待 xff0c 越排越多 需待实验证明
  • SVN的Status字段含义小记

    执行SVN up和svn merge等命令出现在首位置的各字母含义如下 xff1a 无修改 A 新增 C 冲突 D 删除 G 合并 I 忽略 M 改变 R 替换 X 未纳入版本控制 xff0c 但被外部定义所用 未纳入版本控制 该项目已遗失
  • c#中在工作线程创建窗体并操作

    实例1 public void CycleShow 循环绘图 Task Factory StartNew 61 gt threadB 61 new Thread 61 gt AllDealWithSpectrumDicSingle Clea
  • c#绘制星图靶标实例

    public partial class Form2 Form public Form2 InitializeComponent private void button1 Click object sender EventArgs e Ta
  • C#工作线程创建窗体及绘制星图实例

    public partial class Form2 Form public Form2 InitializeComponent private void button1 Click object sender EventArgs e Ta
  • 委托事件的线程问题

    事件注册方法或委托后 xff0c 事件所在的线程执行注册的方法或委托 xff0c 所以如果方法中有跨线程控件就需要使用invoke等处理
  • 怎么判断应用程序是多少位运行的

    C 中 int bitSize 61 IntPtr Size 指针多少字节 if bitSize 61 61 8 MessageBox Show 34 64位程序 34 else if bitSize 61 61 4 MessageBox
  • 图像的色彩类别,灰度化,二值化

    灰度化 xff1a 在RGB模型中 xff0c 如果R 61 G 61 B时 xff0c 则彩色表示一种灰度颜色 xff0c 其中R 61 G 61 B的值叫灰度值 xff0c 因此 xff0c 灰度图像每个像素只需一个字节存放灰度值 xf
  • 服务器与客户端概念

    比如说 xff0c 你浏览百度的网页 xff0c 你的电脑就是客户端 xff0c 而百度网页所存放的机器就是服务器 你通过internet互联网连到百度网页服务器 xff0c 才能浏览网页 再比如说 xff0c 你玩网络游戏 xff0c 你
  • 图像灰度图,直方图,像素通道问题

    1 图像直方图概述 直方图广泛运用于很多计算机视觉运用当中 xff0c 通过标记帧与帧之间显著的边缘和颜色的统计变化 xff0c 来检测视频中场景的变化 在每个兴趣点设置一个有相近特征的直方图所构成 标签 xff0c 用以确定图像中的兴趣点
  • 深入浅出的讲解傅里叶变换(真正的通俗易懂)

    我保证这篇文章和你以前看过的所有文章都不同 xff0c 这是 2012 年还在果壳的时候写的 xff0c 但是当时没有来得及写完就出国了 于是拖了两年 xff0c 嗯 xff0c 我是拖延症患者 这篇文章的核心思想就是 xff1a 要让读者
  • 理解图像傅里叶变换的频谱图

    很多人都不了解图像 xff08 二维 xff09 频谱中的每一点究竟代表了什么 xff0c 有什么意义 一句话解释为 xff1a 二维频谱中的每一个点都是一个与之一 一对应的二维正弦 余弦波 视觉的优势永远大于其他器官对人的作用 xff0c
  • 机器视觉自动数据标注方法

    目录 一 背景阅读 个人总结 xff1a xff08 半 xff09 自动数据标注的方法基本都是采用类似的思路 xff0c 即通过少量标注数据进行训练后得到一个预训练模型 xff0c 然后再次基础上对该网络的输出结果进行人工核验 xff0c
  • 理解图像的傅里叶变换

    最近在看图像的傅里叶变换 xff0c 看着频谱图一直没看明白到底为啥是那样的 xff0c 跟同学研究了好久 xff0c 终于想明白了 感谢同学的耐心指导 xff01 大家相互讨论真的很快就能出结果 xff0c 多讨论 xff0c 多学习 图
  • 快速傅里叶变换(FFT)详解

    快速傅里叶变换 xff08 FFT xff09 详解 xff08 这是我第一次写博 xff0c 不喜勿喷 xff09 关于FFT已经听闻已久了 xff0c 这次终于有机会在Function2的介绍下来了解一下FFT了 快速傅里叶变换 Fas
  • 图像处理:如何理解傅里叶变换在图像处理中的应用

    声明 xff1a 这篇文章的主要目的是通过建立一维傅里叶变换与图像傅里叶变换中相关概念的对应关系来帮助读者理解图像处理中的离散傅里叶变换 xff0c 因此 xff0c 理解图像中离散傅里叶变换的前提条件是读者需要了解一维傅里叶变换的基本知识
  • 图像处理中的傅里叶变换和频率域滤波概念

    写在前面的话 作者是一名在读的硕士研究僧 xff0c 方向是机器视觉 由于视觉是一门相对复杂的学科 xff0c 作者在课堂上学到的东西只是非常浅显的内容 xff0c 我们老师说是 xff0c 领我们进了个门 现在打算利用图书馆和网络上的资源
  • 图像处理的傅里叶变换理解

    傅立叶变换在图像处理中有非常非常的作用 因为不仅傅立叶分析涉及图像处理的很多方面 xff0c 傅立叶的改进算法 xff0c 比如离散余弦变换 xff0c gabor与小波在图像处理中也有重要的分量 印象中 xff0c 傅立叶变换在图像处理以
  • 傅里叶变换分类

    傅里叶变换 傅里叶变换 xff08 Fourier transform xff09 是一种线性的积分变换 xff0c 从时间转换为频率的变化 1 1 连续傅里叶变换 这是将频率域的函数F 表示为时间域的函数f xff08 t xff09 的
  • C++实现二维离散傅里叶变换

    在上一篇文章 C 43 43 实现一维离散傅里叶变换 中 xff0c 我们介绍了一维信号傅立叶变换的公式和C 43 43 实现 xff0c 并阐述了频域幅值的意义 一维傅立叶变换只适用于一维信号 xff0c 例如音频数据 心脑电图等 在图像