原文:Win8 Metro(C#)数字图像处理--2.53图像傅立叶变换



[函数名称]

1,一维FFT变换函数         Complex[] FFT(Complex[] sourceData, int countN)

  2,二维FFT变换函数           Complex[] FFT2(byte[] imageData,bool inv)

  3,图像傅立叶变换幅度函数     WriteableBitmap FFTImage()

  4,图像傅立叶变换相位函数     WriteableBitmap FFTPhaseImage()

[算法说明]

  关于傅立叶变换这一小节,由于算法较为复杂,因此在后面专门介绍,这里略去。

[函数代码]

  代码包括两个类库:1,复数运算类Complex.cs   2,FFT变换类DFT.cs

1.Complex.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Win8ImageProcess
{
class Complex
{
//复数实部
private double real = 0.0;
//复数虚部
private double imaginary = 0.0; public double Real
{
get
{
return real;
}
set
{
real = value;
}
} public double Imaginary
{
get
{
return imaginary;
}
set
{
imaginary = value;
}
} public Complex()
{
} public Complex(double dbreal, double dbimag)
{
real = dbreal;
imaginary = dbimag;
} public Complex(Complex other)
{
real = other.real;
imaginary = other.imaginary;
}
//复数加运算
public static Complex operator +(Complex comp1, Complex comp2)
{
return comp1.Add(comp2);
}
//复数减运算
public static Complex operator -(Complex comp1, Complex comp2)
{
return comp1.Subtract(comp2);
}
//复数乘运算
public static Complex operator *(Complex comp1, Complex comp2)
{
return comp1.Multiply(comp2);
} public Complex Add(Complex comp)
{
double x = real + comp.real;
double y = imaginary + comp.imaginary; return new Complex(x, y);
} public Complex Subtract(Complex comp)
{
double x = real - comp.real;
double y = imaginary - comp.imaginary; return new Complex(x, y);
} public Complex Multiply(Complex comp)
{
double x = real * comp.real - imaginary * comp.imaginary;
double y = real * comp.imaginary + imaginary * comp.real; return new Complex(x, y);
}
//幅值
public double Abs()
{
double x = Math.Abs(real);
double y = Math.Abs(imaginary); if (real == 0)
{
return y;
}
if (imaginary == 0)
{
return x;
} if (x > y)
{
return (x * Math.Sqrt(1 + (y / x) * (y / x)));
}
else
{
return (y * Math.Sqrt(1 + (x / y) * (x / y)));
}
}
//相位角
public double Angle()
{
if (real == 0 && imaginary == 0)
return 0; if (real == 0)
{
if (imaginary > 0)
return Math.PI / 2;
else
return -Math.PI / 2;
}
else
{
if (real > 0)
return Math.Atan2(imaginary, real);
else
{
if (imaginary >= 0)
return Math.Atan2(imaginary, real) + Math.PI;
else
return Math.Atan2(imaginary, real) - Math.PI;
}
}
}
//共轭
public Complex Conjugate()
{
return new Complex(this.real, -this.imaginary);
}
}
}
2.DFT.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Windows.UI.Xaml.Media.Imaging;
using System.Runtime.InteropServices.WindowsRuntime; namespace Win8ImageProcess
{
public sealed class DFTClass
{
private static WriteableBitmap srcImage;
private static byte[] imageData;
private static int w = 0;
private static int h = 0; public DFTClass(WriteableBitmap image)
{
srcImage = image;
w = image.PixelWidth;
h = image.PixelHeight;
}
//一维FFT变换
private Complex[] FFT(Complex[] sourceData, int countN)
{
//求fft的级数
int r = Convert.ToInt32(Math.Log(countN, 2));
//定义加权系数W
Complex[] w = new Complex[countN / 2];
Complex[] interVar1 = new Complex[countN];
Complex[] interVar2 = new Complex[countN];
interVar1 = (Complex[])sourceData.Clone();
//求取加权系数W
double angle = 0;
for (int i = 0; i < countN / 2; i++)
{
angle = -i * Math.PI * 2 / countN;
w[i] = new Complex(Math.Cos(angle), Math.Sin(angle));
angle = 0;
}
int interval = 0;
int halfN = 0;
int gap = 0;
//核心部分
for (int i = 0; i < r; i++)
{
interval = 1 << i;
halfN = 1 << (r - i);
for (int j = 0; j < interval; j++)
{
gap = j * halfN;
for (int k = 0; k < halfN / 2; k++)
{
interVar2[k + gap] = interVar1[k + gap] + interVar1[k + gap + halfN / 2];
interVar2[k + halfN / 2 + gap] = (interVar1[k + gap] - interVar1[k + gap + halfN / 2]) * w[k * interval];
}
}
interVar1 = (Complex[])interVar2.Clone();
}
uint rev = 0;
uint num = 0;
for (uint j = 0; j < countN; j++)
{
rev = 0;
num = j;
for (int i = 0; i < r; i++)
{
rev <<= 1;
rev |= num & 1;
num >>= 1;
}
interVar2[rev] = interVar1[j];
}
return interVar2;
}
//二维fft变换
private Complex[] FFT2(byte[] imageData,bool inv)
{
int bytes = w * h;
byte[] bmpValues = new byte[bytes];
Complex[] tempCom1 = new Complex[bytes];
bmpValues = (byte[])imageData.Clone();
for (int i = 0; i < bytes; i++)
{
if (inv == true)
{
if ((i / w + i % w) % 2 == 0)
{
tempCom1[i] = new Complex(bmpValues[i], 0);
}
else
{
tempCom1[i] = new Complex(-bmpValues[i], 0);
}
}
else
{
tempCom1[i] = new Complex(bmpValues[i], 0);
}
}
Complex[] tempCom2 = new Complex[w];
Complex[] tempCom3 = new Complex[w];
for (int i = 0; i < h; i++)//水平方向
{
for (int j = 0; j < w; j++)
{
tempCom2[j] = tempCom1[i * w + j];
}
tempCom3 = FFT(tempCom2, w);
for (int j = 0; j < w; j++)
{
tempCom1[i * w + j] = tempCom3[j];
}
}
Complex[] tempCom4 = new Complex[h];
Complex[] tempCom5 = new Complex[h];
for (int i = 0; i < w; i++)//垂直方向
{
for (int j = 0; j < h; j++)
{
tempCom4[j] = tempCom1[j * w + i];
}
tempCom5 = FFT(tempCom4, h);
for (int j = 0; j < h; j++)
{
tempCom1[j * w + i] = tempCom5[j];
}
}
return tempCom1;
}
/// <summary>
/// 图像FFT幅度图函数
/// </summary>
/// <returns></returns>
public WriteableBitmap FFTImage()
{
WriteableBitmap grayImage = new WriteableBitmap(w, h);
byte[] temp = srcImage.PixelBuffer.ToArray();
imageData = new byte[w * h];
byte tempByte = 0;
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
tempByte = (byte)((int)(temp[i * 4 + j * w * 4] * 0.114 + temp[i * 4 + 1 + j * w * 4] * 0.587 + temp[i * 4 + 2 + j * w * 4] * 0.299));
imageData[i + j * w] = tempByte;
}
}
int bytes = w * h;
Complex[] freDom = new Complex[bytes];
double[] tempArray = new double[bytes];
freDom = FFT2(imageData, true);
for (int i = 0; i < bytes; i++)
{
tempArray[i] = Math.Log(1 + freDom[i].Abs(), 2);
}
//灰度级拉伸
double a = 1000.0, b = 0.0;
double p;
for (int i = 0; i < bytes; i++)
{
if (a > tempArray[i])
{
a = tempArray[i];
}
if (b < tempArray[i])
{
b = tempArray[i];
}
}
p = 255.0 / (b - a);
for (int i = 0; i < bytes; i++)
{
imageData[i] = (byte)(p * (tempArray[i] - a) + 0.5);
}
byte[] dstData = new byte[w * h * 4];
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
dstData[i * 4 + j * w * 4] = (byte)imageData[i + j * w];
dstData[i * 4 + 1 + j * w * 4] = (byte)imageData[i + j * w];
dstData[i * 4 + 2 + j * w * 4] = (byte)imageData[i + j * w];
}
}
Stream sTemp = grayImage.PixelBuffer.AsStream();
sTemp.Seek(0, SeekOrigin.Begin);
sTemp.Write(dstData, 0, w * 4 * h);
return grayImage;
}
/// <summary>
/// 图像FFT相位图函数
/// </summary>
/// <returns></returns>
public WriteableBitmap FFTPhaseImage()
{
WriteableBitmap grayImage = new WriteableBitmap(w, h);
byte[] temp = srcImage.PixelBuffer.ToArray();
imageData = new byte[w * h];
byte tempByte = 0;
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
tempByte = (byte)((int)(temp[i * 4 + j * w * 4] * 0.114 + temp[i * 4 + 1 + j * w * 4] * 0.587 + temp[i * 4 + 2 + j * w * 4] * 0.299));
imageData[i + j * w] = tempByte;
}
}
int bytes = w * h;
Complex[] freDom = new Complex[bytes];
double[] tempArray = new double[bytes];
freDom = FFT2(imageData, true);
for (int i = 0; i < bytes; i++)
{
tempArray[i] = freDom[i].Angle() + 2 * Math.PI;
}
//灰度级拉伸
double a = 1000.0, b = 0.0;
double p;
for (int i = 0; i < bytes; i++)
{
if (a > tempArray[i])
{
a = tempArray[i];
}
if (b < tempArray[i])
{
b = tempArray[i];
}
}
p = 255.0 / (b - a);
for (int i = 0; i < bytes; i++)
{
imageData[i] = (byte)(p * (tempArray[i] - a) + 0.5);
}
byte[] dstData = new byte[w * h * 4];
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
dstData[i * 4 + j * w * 4] = (byte)imageData[i + j * w];
dstData[i * 4 + 1 + j * w * 4] = (byte)imageData[i + j * w];
dstData[i * 4 + 2 + j * w * 4] = (byte)imageData[i + j * w];
}
}
Stream sTemp = grayImage.PixelBuffer.AsStream();
sTemp.Seek(0, SeekOrigin.Begin);
sTemp.Write(dstData, 0, w * 4 * h);
return grayImage;
}
}
}


Win8 Metro(C#)数字图像处理--2.53图像傅立叶变换的更多相关文章

  1. Win8 Metro(C#)数字图像处理--3.2图像方差计算

    原文:Win8 Metro(C#)数字图像处理--3.2图像方差计算 /// <summary> /// /// </summary>Variance computing. / ...

  2. Win8 Metro(C#)数字图像处理--3.3图像直方图计算

    原文:Win8 Metro(C#)数字图像处理--3.3图像直方图计算 /// <summary> /// Get the array of histrgram. /// </sum ...

  3. Win8 Metro(C#)数字图像处理--3.4图像信息熵计算

    原文:Win8 Metro(C#)数字图像处理--3.4图像信息熵计算 [函数代码] /// <summary> /// Entropy of one image. /// </su ...

  4. Win8 Metro(C#)数字图像处理--3.5图像形心计算

    原文:Win8 Metro(C#)数字图像处理--3.5图像形心计算 /// <summary> /// Get the center of the object in an image. ...

  5. Win8 Metro(C#)数字图像处理--3.1图像均值计算

    原文:Win8 Metro(C#)数字图像处理--3.1图像均值计算 /// <summary> /// Mean value computing. /// </summary> ...

  6. Win8 Metro(C#)数字图像处理--2.74图像凸包计算

    原文:Win8 Metro(C#)数字图像处理--2.74图像凸包计算 /// <summary> /// Convex Hull compute. /// </summary> ...

  7. Win8 Metro(C#)数字图像处理--2.68图像最小值滤波器

    原文:Win8 Metro(C#)数字图像处理--2.68图像最小值滤波器 /// <summary> /// Min value filter. /// </summary> ...

  8. Win8 Metro(C#)数字图像处理--2.52图像K均值聚类

    原文:Win8 Metro(C#)数字图像处理--2.52图像K均值聚类  [函数名称]   图像KMeans聚类      KMeansCluster(WriteableBitmap src,i ...

  9. Win8 Metro(C#)数字图像处理--2.45图像雾化效果算法

    原文:Win8 Metro(C#)数字图像处理--2.45图像雾化效果算法 [函数名称]   图像雾化         AtomizationProcess(WriteableBitmap src,i ...

随机推荐

  1. [Ramda] Create a Query String from an Object using Ramda's toPairs function

    In this lesson, we'll use Ramda's toPairs function, along with map, join, concatand compose to creat ...

  2. NSOperationQueue小结

    将建立的线程增加队列之中.他们都是并发运行的  假设想有一个线程在另外一个线程之后再运行的话 有一个方法能够实现- (void)addDependency:(NSOperation *)op; 这一个 ...

  3. Qt 模仿QQ截图 动态吸附直线

    最近在学Qt.学东西怎么能不动手. 就写了些小程序.看QQ截图能够动态吸附直线的功能挺有意思,所以就模仿了一个. 先上效果图 界面很简单..呵呵 移动鼠标,会把鼠标所在最小矩形选中.把没有选中的地方给 ...

  4. 解决离线Could not parse configuration:hibernate.cfg.xml错误

    离线使用hibernate tool 生成反向工程,在配置 配置文件完,生成配置文件后,会报出org.hibernate.HibernateException: Could not parse con ...

  5. kindeditor 4 指定生成文件的时间日期/动态获取My97的时间

    最近后台要求要指定上传附件的时间日期,编辑器是kindeditor,仔细研究后发现可以借助clickToolbar事件,传递时间到后台,但是中途发现传递的时间总是初始化my97的时间,改变后的时间只有 ...

  6. TensorFlow 学习(四)—— computation graph

    TensorFlow 的计算需要事先定义一个 computation graph(计算图),该图是一个抽象的结构,只有在评估(evaluate)时,才有数值解,这点和 numpy 不同.这张图由一组节 ...

  7. [MFC]SDI在图片背景上实现文本跟随鼠标移动

    SDI是单文档接口应用程序的简称.本文要实现的是在视图区域显示一张图片,然后在图片表层显示文字,并且文字跟随鼠标移动.思考一下,可以判断这个问题一共分为以下几个部分:1.显示图片:2.找到鼠标的位置: ...

  8. UVA 1428 - Ping pong(树状数组)

    UVA 1428 - Ping pong 题目链接 题意:给定一些人,从左到右,每一个人有一个技能值,如今要举办比赛,必须满足位置从左往右3个人.而且技能值从小到大或从大到小,问有几种举办形式 思路: ...

  9. C语言笔试题精选3---死锁发生必要条件是?

    问:以下哪些是死锁发生必要条件? A.相互排斥条件 B.请求和保持 C.不可剥夺 D.循环等待 具体解答: 1.相互排斥使用(资源独占)  一个资源每次仅仅能给一个进程使用 2.不可强占(不可剥夺) ...

  10. Druid 专题

    数据源配置: #datasource #Introductions: https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7 ...