彩色图像的曲线灰度变换



前言

做的数字媒体实验课作业程序,学到不少的新东西,先说题,再细讲。题目要求:参照PhotoShop中的“曲线调整”功能,运用所学知识实现彩色图像的曲线灰度变换。

 

  

  当然我写的没有PS的功能那么强大,只做了简单的伽马变换,先放程序的效果图吧。

 

  

程序分析

处理流程

首先图像处理使用的是OpenCV,图形界面显示使用的C#。 程序为什么使用C#而不用C++写图形界面呢?MFC或Qt写起来肯定更方便,但因为我自己目前在学习WPF,所以正好用来写点这些小程序练练手。 这个程序主要有两部分组成(C#所做的图形界面,C++做的图像处理),首先在WPF中设定伽马值,然后将参数传递给C++程序,完成图像处理,最后C#程序再取回处理之后的图像进行显示。

 

  

难点

1. 程序右上角曲线图表2. C#与C++程序之间的“通信”

解决了以上两点,这个程序剩下的部分就非常简单了,以下主要说明这两个问题。

曲线图表

流程图

 

  

Tips

对于WPF程序,实现这个功能还是不难的。1. 使用什么控件?主要用到Canvas+Thumb控件,Thumb用起来简直不要太爽…(Thumb控件网上资料很多也很全,本文不多说,主要使用到它的三个事件DragStarted、DragDelta、DragCompleted)。

2. 如何画曲线? 线是由点构成的,两点就可以构成直线,而曲线呢,只是稍微点多一些(越多越平滑),然后再将点连接起来,就是一条曲线了。所以通过伽马转换的公式(Y=C*X^γ,C是常数,设定为1),我们就可以得到很多个曲线上的点,再将它们连接起来就是一条曲线了。要注意的是取点的个数,要是太多了,势必会影响到程序运行的效率,太少了又显得曲线不够平滑,所以自己找到一个合适的数量就好了。

3. 如何防止目标点越界? 方法有两种:①判断Thumb控件的坐标(相对于Canvas)②判断鼠标的坐标值(相对于Canvas)。我采用了第二种,优点是实现起来比较简单,缺点是鼠标只能够图表中移动目标点,移除图表后,点不能够跟着鼠标继续在图表边缘移动。不过没多大影响,只是交互性差点。

4. 滑动条如何控制原图与效果图的显示? 这个非常简单,顺带说一说。其实就是两个重叠的Image元素,其中显示效果图的那个Image元素由滑动条控制透明度就可以了,最方便的做法是用元素绑定,将Image的Opacity属性绑定到Slider的值上。

JAVA;">

Opacity="{Binding ElementName=TransparentSlider, Path=Value, Mode=OneWay}"

C#与C++程序“通信”

严格意义上将不能称之为通信,主要是一种调用程序的关系,单向的信息传递。过程是C#程序将需要处理的图片路径、gamm值、处理结果图片路径三个参数传递给C++程序,处理完成后C#程序再去取图片。

那么如何把这些参数传递给C++程序呢? 这个就涉及到进程通信相关内容了(管道通信、共享内存、Socket等),而我没有用那么复杂的技术,有个非常简单的方式,那就是使用命令行参数!经常在C++程序中看到的int main(int argc,char *argv[])其中的int argc代表参数个数,char *argv[]代表参数。然后在C#中使用Process类就可以做到调用应用程序并向其传递参数了。 看一下C#这部分的代码:

JAVA;">

private void TransformImage(double gamm, string imagePath)

{

    //参数 1输入路径 2伽马值 3输出路径

    string argu_srcPath = imagePath;

    string argu_gamm = gamm.ToString();

    string argu_resPath = resImageFilePath;


    Process process = new Process();

    //C++程序所在路径

    process.StartInfo.FileName = currFilePath + "\\Project1.exe";

    process.StartInfo.Arguments = argu_srcPath + " " + argu_gamm + " " + argu_resPath;

    process.StartInfo.UseShellExecute = false;

    process.StartInfo.CreateNoWindow = true;

    process.Start();

    //等待程序执行结束,再继续执行代码

    process.WaitForExit();

    process.Close();

}

而在C++代码中只需要顺序取argv数组中的值即可,得到相应的参数。

写在最后

写过WinForm之后,再用WPF还是非常爽的,尤其是布局用起来太方便了。目前这个程序还是有缺点的,比如现在只做了JPG图片的处理;只做了伽马曲线变换,没有像ps一样支持多点调整(拟合函数)。还需要多多努力啊!项目代码后面打包上传。

猜你喜欢

转载自epoll-select.iteye.com/blog/2406725