• 【WP 8.1开发】How to 图像处理


    在今天的吹牛节目开始之前,先交代一件事:

    关于玩WP 8.1开发所使用的VS版本问题。对版本的要求是2013的Update2,这是最低要求,只要是这个版本或以上都可以,而update3,update4,update5是不是必须更新呢?不是的,VS的update是可选的,而且每个update都会累积,所以,update越多,安装包的体积越大。因此,WP开发我们只需update2就行了,我用的也是u2。如果你觉得MSDN原版不好下,可以从下面的地址下,我已经把相关的.iso上传到115。这里面是旗舰版。

    开发工具
    115网盘礼包码:5lbblgv09y6k
    http://115.com/lb/5lbblgv09y6k

    如果你还没有安装VS,我这里分享一个小技巧。就是在安装时,不要勾选Windows Phone 8.0 SDK,安装后就没有8.0的模拟器和镜像,也不能开发8.0的应用,只能开发8.1的,而且只能用真机调试。

    安装后,你再下载我上面分享的另一个.iso——windowsphone81sdkupdate1.iso,这里不仅包含8.1的SDK,还带了8.1 Update 1的模拟器,即有“小娜”的版本。

    如此一来,你只安装了最新的8.1模拟器,而没有8.0的模拟器了。当然如果你要开发8.0的应用,就要安装Windows Phone 8.0 SDK,我上面说的当你只开发8.1应用的时候用的。

    =======================================================

    好了,吹牛节目正式开始,由于剧组缺钱,本节目的主持人只有老周一人,没有后台工作人员,有点像关老爷单刀赴会的感觉。今天咱们吹一下如何进行图像处理,比如怎么把图片变成灰度、反色、黑色等。

    老周不是专业搞图像的,老周是打酱油专业毕业的,所以老周不懂相关的知识,但不要紧,只要我们好好利用现有的API,也可以对图像进行一些非专业性处理。我们可以不明白图像文件的具体结构,只要懂得如何改写像素数据就行了。

    要弄清楚像素数据是如何排列的,首先要简单理解一下常见的像素格式是啥样的。这些格式由Windows.Graphics.Imaging.BitmapPixelFormat枚举定义,Unknown成员不管它,我们只关心另外三个。

    Bgra8——最后面的8表示8位,即每个颜色值占8位,也就是1字符,bgra,第一个字节表示B(蓝)的值,第二个字节表示G(绿)的值,第三个字节表示R(红)的值,第四个字节表示A(不透明度)的值。举个例子,假设有一个图片里面有四个像素,宽为2,高为2,即两行两列。结构如下表所示:

    R = 100

    G = 0

    B = 200

    A = 255

    R = 255

    G = 50

    B = 32

    A = 255

    R = 12

    G = 30

    B = 90

    A = 255

    R = 120

    G = 60

    B = 75

    A = 255

     像素数据是一个字符数组,比如上面的2*2的图像,转换为像素数据为:

    {
       200, 0, 100, 255,   32, 50, 255, 255   ……  75, 64, 120, 255
    }

    因为像素格式为bgra,所以排第一的是B的值,接着是G,然后是R,最后是A,也就是说,每四个字节表示一个像素点,上述例子中,图像有四个像素点,每个点由4个字节表示,所以整个图像的像素数据共4*4=16字节。

    字节的排列就是按像素点顺序排放的,从左到右,从上到下,先排完第一行,再排第二行,第三行……一直排到最后一个像素点。

    Rgba8……和上面的一样,每个颜色值占一个字节,只是排列时顺序不同,rgba是最常用的,因为这样排列图像不会偏色,即第一个字节是R,第二个字节是G,第三个字节是B,最后是A。这个RGB的通道不同顺序产生的不同效果,大家可以在PS里面查看,PS中“图层”窗口中有个“通道”面板,那里可以看到各个通道的效果。

    Rgba16——和上面一样,排列顺序也是R -> G -> B -> A,但是,rgba16中每个色值为16位,即占用2个字节。在像素数据中,第一个和第二个字节共同表示R值;第三个,第四个字节共同表示G的值;第五个第六个字节为B的值,第七、八个字节表示A。这个模式很少用,因为不太好套公式,呵呵。

    理论知识还是抽象的,咱们来干点实事吧。下面老周给大家演示两个比较简单的处理——灰度 和 反色。

    图像处理的各种方法大家可以查书,可以网上查,反正都有固定公式的。

    1、灰度处理。

    这里我选用平均法,即把每个像素点中R,G,B三个值进行相加,然后除以3,再把这个平均后的值替换原来的R,G,B值,A是不透明度,一般可以不管它,生成新的像素数据值时A值就用原图的A值就行了,主要是针对RGB进行计算。代码如下:

            /// <summary>
            /// 灰度处理
            /// </summary>
            private byte[] GrayScale(byte[] rgbaBuff)
            {
                byte[] resbytes = new byte[rgbaBuff.Length];
                for (int i = 0; i < rgbaBuff.Length; i += 4)
                {
                    byte r = rgbaBuff[i];
                    byte g = rgbaBuff[i + 1];
                    byte b = rgbaBuff[i + 2];
                    byte a = rgbaBuff[i + 3];
                    // 使用平均法
                    byte ev = Convert.ToByte((Convert.ToDouble(r) + Convert.ToDouble(g) + Convert.ToDouble(b)) / 3d);
                    // 生成新的像素值
                    resbytes[i] = resbytes[i + 1] = resbytes[i + 2] = ev;
                    resbytes[i + 3] = a;
                }
                return resbytes;
            }


    我的示例都是用rgba8格式的,每个像素点需要4个字节,所以在for循环中,i的境量不是i++,而是i += 4,即每次循环跳4个字节,这样才能保证每一轮循环都访问一个像素点。

    2、反色。

    反色最简单,分别用255去減RGB三个值就行了,即

    newR = 255 - oldR, newG= 255 - oldG, newB= 255-oldB

            /// <summary>
            /// 反色
            /// </summary>
            private byte[] InvertPixels(byte[] rgbaBuff)
            {
                byte[] res = new byte[rgbaBuff.Length];
                for (int i = 0; i < rgbaBuff.Length; i += 4)
                {
                    byte r = rgbaBuff[i];
                    byte g = rgbaBuff[i + 1];
                    byte b = rgbaBuff[i + 2];
                    byte a = rgbaBuff[i + 3];
                    // 反色就是用255分别减去R,G,B的值
                    res[i] = (byte)(255 - r);
                    res[i + 1] = (byte)(255 - g);
                    res[i + 2] = (byte)(255 - b);
                    res[i + 3] = a;
                }
                return res;
            }

    3、获取源图像的像素数据。

    要得到源图像的像素数据,需要先对图像进行解码,这个应该很多观众都会,就是用Windows.Graphics.Imaging.BitmapDecoder类来解码。

    我建议大家通过帧来获取单帧图像的像素数据,一般来说,静态图片只有一帧,所以调用BitmapDecoder实例的GetFrameAsync(0)方法就能得到第一帧的图像,由BitmapFrame类封装,再通过BitmapFrame实例的GetPixelDataAsync方法得到一个PixelDataProvider实例,再访问PixelDataProvider实例的DetachPixelData方法就能得到表示像素数据的字节数组。

            enum OperType { Gray, Invert };
    
            private async Task<BitmapSource> ImageToProcAsync(IRandomAccessStream inputStream, OperType opt)
            {
                BitmapDecoder decoder = await BitmapDecoder.CreateAsync(BitmapDecoder.JpegDecoderId, inputStream);
                // 获取第一帧
                BitmapFrame frame = await decoder.GetFrameAsync(0);
                // 获取像素数据
                PixelDataProvider pixprd = await frame.GetPixelDataAsync(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, new BitmapTransform(), ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage);
                byte[] data = pixprd.DetachPixelData();
                // 处理
                byte[] returnData = null;
                if (opt == OperType.Gray)
                {
                    returnData = GrayScale(data);
                }
                else
                {
                    returnData = InvertPixels(data);
                }
                // 创建新的位图对象
                WriteableBitmap wb = new WriteableBitmap((int)frame.PixelWidth, (int)frame.PixelHeight);
                // 复制数据
                returnData.CopyTo(wb.PixelBuffer);
                return wb;
            }

    OperType是自定义枚举,Gray表示灰度处理,Invert表示反色处理。

    最后,请各位观众一起看看效果吧。

         

    各位观众,感谢您收看由火星电视台转播的老周吹牛节目,本集示例的源代码稍后给出下载地址。Thank you.

    示例下载:http://files.cnblogs.com/tcjiaan/imgProcSampleApp.zip

    欢迎下个世纪同一时间,准时收看老周吹牛特别节目。本节目由火星移动有限公司独家赞助。

    88。

  • 相关阅读:
    json、txt、xlsx
    word-排版准备与文字清洗
    运营能力分析
    获利能力分析
    偿债能力分析
    现金流量表结构分析
    负债项目分析
    资产负债表分析
    财务报表的分析
    会计电算化账务处理流程8
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/4231886.html
Copyright © 2020-2023  润新知