数字图像处理-离散傅里叶变换(opencv3+C++显示)

2023-11-14

参考:

http://daily.zhihu.com/story/3935067

http://blog.csdn.net/keith_bb/article/details/53389819

在学习信号与系统或通信原理等课程里面可能对傅里叶变换有了一定的了解。我们知道傅里叶变换是把一个信号从时域变换到其对应的频域进行分析。如果有小伙伴还对傅里叶变换处于很迷糊的状态,请戳这里,非常通俗易懂。而在图像处理中也有傅里叶分析的概念,我这里给出在其官方指导文件opencv_tutorials中给出的解释。 
傅里叶变换可以将一幅图片分解为正弦和余弦两个分量,换而言之,他可以将一幅图像从其空间域(spatial domain)转换为频域(frequency domain)。这种变换的思想是任何函数可以很精确的接近无穷个sin()函数和cos()函数的和。傅里叶变换提供了这种方法来达到这种效果。对于二位图像其傅里叶变换公式如下: 
这里写图片描述 
式中f(i, j)是图像空间域的值而F是频域的值。傅里叶转换的结果是复数,这也显示出了傅里叶变换是一副实数图像(real image)和虚数图像(complex image)叠加或者是幅度图像(magitude image)和相位图像(phase image)叠加的结果。在实际的图像处理算法中仅有幅度图像(magnitude image)图像能够用到,因为幅度图像包含了我们所需要的所有图像几何结构的信息。但是,如果想通过修改幅度图像或者相位图像来间接修改原空间图像,需要保留幅度图像和相位图像来进行傅里叶逆变换,从而得到修改后图像。

1.dft()

首先看一下opencv提供的傅里叶变换函数dft(),其定义如下:

C++: void dft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0);
   
   
  • 1

参数解释: 
. InputArray src: 输入图像,可以是实数或虚数 
. OutputArray dst: 输出图像,其大小和类型取决于第三个参数flags 
. int flags = 0: 转换的标识符,有默认值0.其可取的值如下所示: 
。DFT_INVERSE: 用一维或二维逆变换取代默认的正向变换 
。DFT_SCALE: 缩放比例标识符,根据数据元素个数平均求出其缩放结果,如有N个元素,则输出结果以1/N缩放输出,常与DFT_INVERSE搭配使用。 
。DFT_ROWS: 对输入矩阵的每行进行正向或反向的傅里叶变换;此标识符可在处理多种适量的的时候用于减小资源的开销,这些处理常常是三维或高维变换等复杂操作。 
。DFT_COMPLEX_OUTPUT: 对一维或二维的实数数组进行正向变换,这样的结果虽然是复数阵列,但拥有复数的共轭对称性(CCS),可以以一个和原数组尺寸大小相同的实数数组进行填充,这是最快的选择也是函数默认的方法。你可能想要得到一个全尺寸的复数数组(像简单光谱分析等等),通过设置标志位可以使函数生成一个全尺寸的复数输出数组。 
。DFT_REAL_OUTPUT: 对一维二维复数数组进行逆向变换,这样的结果通常是一个尺寸相同的复数矩阵,但是如果输入矩阵有复数的共轭对称性(比如是一个带有DFT_COMPLEX_OUTPUT标识符的正变换结果),便会输出实数矩阵。 
. int nonzeroRows = 0: 当这个参数不为0,函数会假设只有输入数组(没有设置DFT_INVERSE)的第一行或第一个输出数组(设置了DFT_INVERSE)包含非零值。这样的话函数就可以对其他的行进行更高效的处理节省一些时间,这项技术尤其是在采用DFT计算矩阵卷积时非常有效。

2. getOptimalDFTSize()

返回给定向量尺寸经过DFT变换后结果的最优尺寸大小。其函数定义如下:

C++: int getOptimalDFTSize(int vecsize);
   
   
  • 1

参数解释: 
int vecsize: 输入向量尺寸大小(vector size) 
DFT变换在一个向量尺寸上不是一个单调函数,当计算两个数组卷积或对一个数组进行光学分析,它常常会用0扩充一些数组来得到稍微大点的数组以达到比原来数组计算更快的目的。一个尺寸是2阶指数(2,4,8,16,32…)的数组计算速度最快,一个数组尺寸是2、3、5的倍数(例如:300 = 5*5*3*2*2)同样有很高的处理效率。 
getOptimalDFTSize()函数返回大于或等于vecsize的最小数值N,这样尺寸为N的向量进行DFT变换能得到更高的处理效率。在当前N通过p,q,r等一些整数得出N = 2^p*3^q*5^r. 
这个函数不能直接用于DCT(离散余弦变换)最优尺寸的估计,可以通过getOptimalDFTSize((vecsize+1)/2)*2得到。

3.magnitude()

计算二维矢量的幅值,其定义如下:

C++: void magnitude(InputArray x, InputArray y, OutputArray magnitude);
   
   
  • 1

参数解释: 
. InputArray x: 浮点型数组的x坐标矢量,也就是实部 
. InputArray y: 浮点型数组的y坐标矢量,必须和x尺寸相同 
. OutputArray magnitude: 与x类型和尺寸相同的输出数组 
其计算公式如下: 
这里写图片描述

4. copyMakeBorder() 
扩充图像边界,其函数定义如下:

C++: void copyMakeBorder(InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar& value=Scalar() );
   
   
  • 1

参数解释: 
. InputArray src: 输入图像 
. OutputArray dst: 输出图像,与src图像有相同的类型,其尺寸应为Size(src.cols+left+right, src.rows+top+bottom) 
. int类型的top、bottom、left、right: 在图像的四个方向上扩充像素的值 
. int borderType: 边界类型,由borderInterpolate()来定义,常见的取值为BORDER_CONSTANT 
. const Scalar& value = Scalar(): 如果边界类型为BORDER_CONSTANT则表示为边界值

5. normalize() 
归一化就是把要处理的数据经过某种算法的处理限制在所需要的范围内。首先归一化是为了后面数据处理的方便,其次归一化能够保证程序运行时收敛加快。归一化的具体作用是归纳同意样本的统计分布性,归一化在0-1之间是统计的概率分布,归一化在某个区间上是统计的坐标分布,在机器学习算法的数据预处理阶段,归一化也是非常重要的步骤。其定义如下:

C++: void normalize(InputArray src, OutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() )
   
   
  • 1

参数解释: 
. InputArray src: 输入图像 
. OutputArray dst: 输出图像,尺寸大小和src相同 
. double alpha = 1: range normalization模式的最小值 
. double beta = 0: range normalization模式的最大值,不用于norm normalization(范数归一化)模式 
. int norm_type = NORM_L2: 归一化的类型,主要有 
。NORM_INF: 归一化数组的C-范数(绝对值的最大值) 
。NORM_L1: 归一化数组的L1-范数(绝对值的和) 
。NORM_L2: 归一化数组的L2-范数(欧几里得) 
。NORM_MINMAX: 数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。 
. int dtype = -1: 当该参数为负数时,输出数组的类型与输入数组的类型相同,否则输出数组与输入数组只是通道数相同,而depth = CV_MAT_DEPTH(dtype) 
. InputArray mask = noArray(): 操作掩膜版,用于指示函数是否仅仅对指定的元素进行操作。

示例程序:

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat I = imread("lena.jpg", IMREAD_GRAYSCALE);       //读入图像灰度图

    //判断图像是否加载成功
    if (I.empty())
    {
        cout << "图像加载失败!" << endl;
        return -1;
    }
    else
        cout << "图像加载成功!" << endl << endl;

    Mat padded;                 //以0填充输入图像矩阵
    int m = getOptimalDFTSize(I.rows);
    int n = getOptimalDFTSize(I.cols);

    //填充输入图像I,输入矩阵为padded,上方和左方不做填充处理
    copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));

    Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(),CV_32F) };
    Mat complexI;
    merge(planes, 2, complexI);     //将planes融合合并成一个多通道数组complexI

    dft(complexI, complexI);        //进行傅里叶变换

    //计算幅值,转换到对数尺度(logarithmic scale)
    //=> log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
    split(complexI, planes);        //planes[0] = Re(DFT(I),planes[1] = Im(DFT(I))
                                    //即planes[0]为实部,planes[1]为虚部
    magnitude(planes[0], planes[1], planes[0]);     //planes[0] = magnitude
    Mat magI = planes[0];

    magI += Scalar::all(1);
    log(magI, magI);                //转换到对数尺度(logarithmic scale)

    //如果有奇数行或列,则对频谱进行裁剪
    magI = magI(Rect(0, 0, magI.cols&-2, magI.rows&-2));

    //重新排列傅里叶图像中的象限,使得原点位于图像中心
    int cx = magI.cols / 2;
    int cy = magI.rows / 2;

    Mat q0(magI, Rect(0, 0, cx, cy));       //左上角图像划定ROI区域
    Mat q1(magI, Rect(cx, 0, cx, cy));      //右上角图像
    Mat q2(magI, Rect(0, cy, cx, cy));      //左下角图像
    Mat q3(magI, Rect(cx, cy, cx, cy));     //右下角图像

    //变换左上角和右下角象限
    Mat tmp;
    q0.copyTo(tmp);
    q3.copyTo(q0);
    tmp.copyTo(q3);

    //变换右上角和左下角象限
    q1.copyTo(tmp);
    q2.copyTo(q1);
    tmp.copyTo(q2);

    //归一化处理,用0-1之间的浮点数将矩阵变换为可视的图像格式
    normalize(magI, magI, 0, 1, CV_MINMAX);

    imshow("输入图像", I);
    imshow("频谱图", magI);
    waitKey(0);


    return 0;
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

程序分析: 
1.图像填充:

Mat padded;
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols);
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));
   
   
  • 1
  • 2
  • 3
  • 4

根据前面的理论介绍可以知道当图像尺寸为2、3、5的倍数时可以得到最快的处理速度,所以通过getOptimalDFTSize()函数获取最佳DFT变换尺寸,之后再结合copyMakeBorder()函数对图像进行扩充。

2.为实部和虚部分配存储空间

Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(),CV_32F) };
Mat complexI;
merge(planes, 2, complexI);
   
   
  • 1
  • 2
  • 3

傅里叶变换的结果是复数,这就意味着经过傅里叶变换每个图像值都会变成两个值,此外其频域(frequency domains)范围比空间域(spatial counterpart)范围大很多。我们通常以浮点型数据格式对结果进行存储。因此我们将输入图像转换为这种类型,通过另外的通道扩充图像。

3.傅里叶变换

dft(complexI, complexI);
   
   
  • 1

傅里叶变换函数,对图像进行傅里叶变换。

4.将实数和复数的值转换为幅度值

split(complexI, planes);
magnitude(planes[0], planes[1], planes[0]); 
Mat magI = planes[0];
   
   
  • 1
  • 2
  • 3

复数包含实部和虚部两个部分,傅里叶变换的结果是一个复数,傅里叶变换的幅度计算公式是: 
这里写图片描述 
5.转换为对数尺度(Switch to a logarithmic scale)

magI += Scalar::all(1);
log(magI, magI);
   
   
  • 1
  • 2

之所以要进行对数转换是因为傅里叶变换后的结果对于在显示器显示来讲范围比较大,这样的话对于一些小的变化或者是高的变换值不能进行观察。因此高的变化值将会转变成白点,而较小的变化值则会变成黑点。为了能够获得可视化的效果,可以利用灰度值将我们的线性尺度(linear scale)转变为对数尺度(logarithmic scale),其计算公式如下: 
这里写图片描述

6.剪切和象限变换

magI = magI(Rect(0, 0, magI.cols&-2, magI.rows&-2));
int cx = magI.cols / 2;
int cy = magI.rows / 2;

Mat q0(magI, Rect(0, 0, cx, cy));
Mat q1(magI, Rect(cx, 0, cx, cy));  
Mat q2(magI, Rect(0, cy, cx, cy));
Mat q3(magI, Rect(cx, cy, cx, cy)); 

//变换左上角和右下角象限
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);

//变换右上角和左下角象限
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在进行傅里叶变换时,为了取得更快的计算效果,对图像进行了扩充,现在就需要对新增加的行列进行裁剪了。为了可视化的需要,我们同样需要对显示的结果图像像素进行调整,如果不进行调整,最后显示的结果是这样的: 
这里写图片描述 
可以看到四周的角上时高频分量,现在我们通过重新调整象限将高频分量调整到图像正中间。

7.归一化

normalize(magI, magI, 0, 1, CV_MINMAX);
   
   
  • 1

对结果进行归一化处理同样是处于可视化的目的。现在我们得到了幅度值,但是这仍然超出了0-1的显示范围。这就需要利用normalize()函数对数据进行归一化处理。

程序运行结果如图: 
这里写图片描述

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

数字图像处理-离散傅里叶变换(opencv3+C++显示) 的相关文章

  • 来自连接到远程机器的相机的 Opencv 流

    我正在用 python 开发一个 wx 应用程序 用于流式传输和显示来自两个不同网络摄像头的视频 这工作正常 但现在我需要在不同的场景中执行此操作 其中两个摄像头连接在通过网络连接的 Windows 上运行的单独计算机中 我的应用程序将在机
  • 使用 ffmpeg 或 OpenCV 处理原始图像

    看完之后维基百科页面 http en wikipedia org wiki Raw image format原始图像格式 是任何图像的数字负片 为了查看或打印 相机图像传感器的输出具有 进行处理 即转换为照片渲染 场景 然后以标准光栅图形格
  • 检查图像中是否有太薄的区域

    我正在尝试验证雕刻机的黑白图像 更多的是剪贴画图像 不是照片 我需要考虑的主要事情之一是区域的大小 或线条的宽度 因为机器无法处理太细的线条 所以我需要找到比给定阈值更细的区域 以此图为例 竖琴的琴弦可能太细而无法雕刻 我正在阅读有关 Ma
  • OpenCV 2.3 与 VS 2008 - 鼠标事件

    强制性 我是新手 有一份涉及编程的工作 并且我一边工作一边自学 不用说 作为一名老师 我经常犯彻底的错误 我现在所处的位置 我创建了 Graph 类 它 令人惊讶的是 制作了图表 但现在我想通过单击鼠标来修改图形 但我似乎无法让鼠标处理程序
  • minAreaRect OpenCV 返回的裁剪矩形 [Python]

    minAreaRectOpenCV 中返回一个旋转的矩形 如何裁剪矩形内图像的这部分 boxPoints返回旋转矩形的角点的坐标 以便可以通过循环框内的点来访问像素 但是在 Python 中是否有更快的裁剪方法 EDIT See code在
  • OpenCV 2.4.3 中的阴影去除

    我正在使用 OpenCV 2 4 3 最新版本 使用内置的视频流检测前景GMG http docs opencv org modules gpu doc video html highlight gmg gpu 3a 3aGMG GPU算法
  • 使用 OpenCV 和/或 Numpy 对两个图像进行 Alpha 混合 [重复]

    这个问题在这里已经有答案了 我想将一个填充纯色的半透明矩形添加到已加载的半透明 PNG 中 这是我正在使用的输入图像示例 该图像加载了标准cv2 IMREAD UNCHANGED标志 以便完美保留 alpha 通道 该输入图像存储在imag
  • 2d 图像点和 3d 网格之间的交点

    Given 网格 源相机 我有内在和外在参数 图像坐标 2d Output 3D 点 是从相机中心发出的光线穿过图像平面上的 2d 点与网格的交点 我试图找到网格上的 3d 点 This is the process From Multip
  • 如何绘制更大的边界框和仅裁剪边界框文本 Python Opencv

    我正在使用 easyocr 来检测图像中的文本 该方法给出输出边界框 输入图像如下所示 Image 1 Image 2 使用下面的代码获得输出图像 But I want to draw a Single Bigger bounding bo
  • OpenCV Mat 和 Leptonica Pix 之间的转换

    我需要在 C 中在 OpenCV Mat 图像和 Leptonica Pix 图像格式之间进行转换 这用于 8 位灰度图像的二值化 我发现发现了 ikaliga的回答 https stackoverflow com a 25929320 2
  • OpenCV VideoWriter 未写入 Output.avi

    我正在尝试编写一段简单的代码来获取视频 裁剪视频并写入输出文件 系统设置 OS Windows 10 Conda Environment Python Version 3 7 OpenCV Version 3 4 2 ffmpeg Vers
  • 如何在 cv2.VideoWriter 中使用 FPS 参数?

    好的 所以我正在制作视频 我想确切地知道如何使用 FPS 参数 它是一个浮点数 所以我假设这是我想要的每帧之间的间隔 你能给个例子吗 我只想知道视频会如何随着 FPS 参数值的变化而变化 因为我制作的视频现在太快了 谢谢 确实只是这样 fr
  • 在 Visual Studio C++ 2008 中包含 dll

    有没有办法将 dll 包含在项目中 这样我就不必在编译后将这些 dll 与可执行文件放在同一文件夹中 这样我就可以用它们编译我的项目 这是否有可能 如果是 有人可以指导我 我的项目是一个 opencv 项目 有很多 dll 我必须包含在文件
  • OpenCv读/写视频色差

    我试图简单地使用 openCV 打开视频 处理帧并将处理后的帧写入新的视频文件 我的问题是 即使我根本不处理帧 只是打开视频 使用 VideoCapture 读取帧并使用 VideoWriter 将它们写入新文件 输出文件看起来比输入更 绿
  • 查找具有不同强度/亮度的相似图像

    假设我有如下图像 我可以选择什么来比较两个图像之间的相似度 显然它们是相同的图像 只是亮度不同 我找不到任何可行的方法 目前我最好的选择是训练 cnn 或自动编码器并比较输出的特征向量 但这似乎有点矫枉过正 任何提示将不胜感激 相当强大的工
  • 如何检测斑点并将其裁剪成 png 文件?

    我一直在开发一个网络应用程序 我陷入了一个有问题的问题 我会尝试解释我想要做什么 在这里您看到第一个大图像 其中有绿色形状 我想要做的是将这些形状裁剪成不同的 png 文件 并使它们的背景透明 就像大图像下面的示例裁剪图像一样 第一张图像将
  • 如何加速 svm.predict?

    我正在编写一个滑动窗口来提取特征并将其输入到 CvSVM 的预测函数中 然而 我偶然发现 svm predict 函数相对较慢 基本上 窗口以固定的步幅长度在图像比例上滑动穿过图像 遍历图像加上提取每个图像特征的速度 窗口大约需要 1000
  • 使用卡尔曼滤波器跟踪位置和速度

    我正在使用卡尔曼滤波器 恒定速度模型 来跟踪物体的位置和速度 我测量对象的 x y 并跟踪 x y vx vy 这是有效的 但是如果在传感器读数 x y vx vy 上添加 20 mm 的高斯噪声 即使该点没有移动 只是噪声也会发生波动 对
  • 如何检测图像是否像素化

    之前有人在 SO 上提出过这样的问题 在Python中检测像素化图像 https stackoverflow com questions 12942365 detecting a pixelated image in python还有关于q
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o

随机推荐

  • 第二章:预备知识整理 ——2.1数据操作

    数据操作的课后练习题 2 1 8 练习 运行本节中的代码 将本节中的条件语句 X Y 更改为 X lt Y 或 X gt Y 然后看看你可以得到什么样的张量 用其他形状 例如三维张量 替换广播机制中按元素操作的两个张量 结果是否与预期相同
  • 解决eclipse maven 项目重新下载包这个问题

    本文转载至 http www cnblogs com huzi007 p 5602063 html 问题 eclipse项目使用maven下载依赖包 但是有时候断网什么来着就不会自动下载了 挺蛋疼了 所以 需要我们重新更新项目下载呢 首先是
  • Android PowerSupply (四)ChargeIC SGM41511 IC driver调试

    目录 Android PowerSupply 一 总概 Android PowerSupply 二 power supply core Android PowerSupply 三 power supply sys Android Power
  • IDEA 自动生成 serialVersionUID 的设置

    1 没有设置之前 选中对应的类名 然后按 alt enter 快捷键 的情况如下所示 2 设置自动生成 serialVersionUID 的方式如下图所示 关键点已逐个标识 3 设置之后 选中对应的类名 然后按 alt enter 快捷键
  • 分布式版本控制工具--Git

    分布式版本控制 Git的灵魂使用 版本控制简介 集中式版本控制 分布式版本控制 Git安装 Git的常用命令 Git配置项 新建仓库 增加 删除文件 提交文件 Git分支 Git的标签 查看信息 远程同步 撤销 版本控制简介 集中式版本控制
  • Vector容器的底层实现

    Vector容器的底层实现 Vector 类成员 构造函数 拷贝构造函数和析构函数 迭代器 函数功能 完整代码 总结 Vector Vector同样是STL六大组件之一 简单来讲他就是一个封装了动态大小数组的顺序容器 同时他可以存入各种各样
  • vue elementUI实现双(多)列表格,内容均自定义

    需求类似这样的 使用普通table实现 样式需要自己设置 table class person info border 1 cellspacing 0 tbody tr th 档案编号 th td personInfo name td th
  • 巴比特

    摘要 之前 由于没法开放注册 中国大模型厂商其实一直束手束脚 而8月31日 北京 上海率先通过了大模型备案 这意味着 跑得快 的企业可以大胆向市场推出产品了 从靠PPT来嘴花花 到放开手脚大干一场 大模型厂商们走向了真正的战场 争用户 抢市
  • LeetCode (二)找出数组中多于半数的数字

    题目 给定一个大小为 n 的数组 找到其中的多数元素 多数元素是指在数组中出现次数 大于 n 2 的元素 解法 自己的解法 思路 for循环遍历存Map 记录key对应的Count 如果大于半数 返回 package com jzj stu
  • React v16.3新生命周期、性能优化及注意事项

    欢迎点击领取 前端面试题进阶指南 前端登顶之巅 最全面的前端知识点梳理总结 React Version 16 3版本对组件的生命周期函数进行了一些修改 在每个react组件中都有以下几个生命周期方法 我们应该掌握最新生命周期 学以致用 以达
  • mciSendString函数简介(播放音乐以及录音相关操作)

    函数功能 播放多媒体音乐 视频等 mciSendString是用来播放多媒体文件的API指令 可以播放MPEG AVI WAV MP3 等等 这个函数有自己的mci指令 可以通过不同的指令实现不同的功能 这里我会详细讲解mciSendStr
  • qemu 启动自定义文件系统命令

    kvm qemu aarch64 bin qemu system aarch64 M virt smp 8 cpu cortex a76 m 4G nographic kernel out kernel arm64 Image append
  • 对以太网粗略理解

    1 以太网定义 以太网 Ethernet 指的是由 Xerox公司创建并由Xerox Intel和 DEC公司联合开发的基带局域网规范 通用的以太网标准于1980年9月30日出台 是当今现有局域网采用的最通用的通信协议标准 是局域网的一种
  • html+css+javascript学习总结

    html用来写页面的结构和内容 css写样式和呈现效果 javascript写行为和动作 1 html常用标签 a 超链接 div 盒子 常用来控制样式的 ul ol 无序列表和有序列表 img 图片标签 button 按钮 form 表单
  • 看懂影片标题,各种电影视频格式标题的含义

    一 资源片源解析 根据命名 可以知道资源的来源 从而判断资源画质的好坏 1 CAM 枪版 珍爱生命 远离枪版 CAM通常是用数码摄像机从电影院盗录 有时会使用小三角架 但大多数时候不可能使用 所以摄像机会抖动 因此我们看到画面通常偏暗 人物
  • 【免费】win7 所有.net framework框架集合,免费下载,若要运行此应用程序,您必须首先安装net framework如何解决

    运行软件缺失框架 若要运行此应用程序 您必须首先安装net framework如何解决 那天我看见网上下载一个框架都要收费还要100大洋 现在真的是干啥都要钱 索性就整理了一个全库供大家下载 做点好事 net 框架所有的 net官网下载地址
  • 摄像机标定到底是在干什么?

    2017年11月13日学习记录 机器视觉 1 摄像机标定概括 刚开始学机器视觉 我研究的方向主要是双目视觉测距 做机器视觉的肯定对摄像机标定并不陌生 我入坑一个月 开始就是看看书 论文 了解了大概流程和研究主要方法 无特别明确目的和压力 然
  • 关于Redis的Zset使用方法

    序言 Zset跟Set之间可以有并集运算 因为他们存储的数据字符串集合 不能有一样的成员出现在一个zset中 但是为什么有了set还要有zset呢 zset叫做有序集合 而set是无序的 zset怎么做到有序的呢 就是zset的每一个成员都
  • Java基础:简单的Runnable 接口创建线程

    创建一个线程 Java 提供了三种创建线程的方法 通过实现 Runnable 接口 通过继承 Thread 类本身 通过 Callable 和 Future 创建线程 为了实现 Runnable 一个类只需要执行一个方法调用 run 声明如
  • 数字图像处理-离散傅里叶变换(opencv3+C++显示)

    参考 http daily zhihu com story 3935067 http blog csdn net keith bb article details 53389819 在学习信号与系统或通信原理等课程里面可能对傅里叶变换有了一