在C#用指针实现快速图像处理

作者:V君 发布于:2014-3-31 11:04 Monday 分类:挖坑经验

先展示一下效果

Cdf 均衡, 算法参考自维基百科 直方图均衡化 条目

点击查看原图

平均范围均衡, 自己写的算法

点击查看原图

 

点击查看原图

点击查看原图

平均Yuv亮度均衡 色彩方面略比RGB均衡好些 转换公式参考了维基百科的 YUV 条目.

(我不会说跌了好几跤,因为忘记clip,转出各种奇怪的颜色 )

点击查看原图

 

 

最后是代码, 不解释 乂D

using System;

using System.Collections.Generic;

using System.Drawing;

using System.Drawing.Imaging;

using System.Linq;

using System.Runtime.InteropServices;

using System.Text;

 

namespace SS

{

    static class ImageProcess

    {

 

        //---- utils

 

        private static Bitmap Make32bppRgbCopy(this Image img)

        {

            var bmp = new Bitmap(img.Widthimg.Height

                , PixelFormat.Format32bppRgb);

 

            using (var grp = Graphics.FromImage(bmp))

                grp.DrawImage(imgnew Rectangle(Point.Emptyimg.Size));

 

            return bmp;

        }

 

        public static BitmapData LockEntire(this Bitmap bmpImageLockMode modePixelFormat pf)

        {

            return bmp.LockBits(new Rectangle(Point.Emptybmp.Size), modepf);

        }

 

        public static BitmapData LockEntire32Rgb(this Bitmap bmp)

        {

            return bmp.LockEntire(ImageLockMode.ReadWritePixelFormat.Format32bppRgb);

        }

 

        public static BitmapData LockEntire32RgbR(this Bitmap bmp)

        {

            return bmp.LockEntire(ImageLockMode.ReadOnlyPixelFormat.Format32bppRgb);

        }

 

 

 

        private unsafe static void CalcChannel(byte* origbyte* destint param)

        {

            if (param == 256)

            {

                *dest = *orig;

            }

            else if (param < 256)

            {

                *dest = (byte)(*orig * (param / 255f));

            }

            else if (param > 256)

            {

                var ava = (255 - *orig);

                var pva = (param - 256);

                var ppe = (pva / 255f);

                var adv = ava * ppe;

                *dest = (byte)(adv + *orig);

            }

        }

 

        private static byte Clip(float value)

        {

            if (value < byte.MinValuereturn byte.MinValue;

            if (value > byte.MaxValuereturn byte.MaxValue;

 

            return (byte)Math.Round(value);

        }

 

        //---- base cls

 

        private abstract unsafe class ImageProcessor

        {

            protected delegate void ProcessPixel(int pxint pybyte* rbyte* gbyte* b);

 

            protected void ProcessImageInternal(BitmapData lckProcessPixel ProcessPixel)

            {

                var ptr0 = (byte*)lck.Scan0.ToPointer();

                byte* ptrLineptrPixrgb;

 

                for (int i = 0i < lck.Height++i)

                {

                    ptrLine = ptr0 + (i * lck.Stride);

 

                    for (int j = 0j < lck.Width++j)

                    {

                        ptrPix = ptrLine + (j * 4);

                        b = ptrPix + 0;

                        g = ptrPix + 1;

                        r = ptrPix + 2;

 

                        ProcessPixel(jirgb);

                    }

                }

            }

 

            public abstract Image ProcessImage(Image img);

        }

 

        private abstract unsafe class YuvImageProcessor : ImageProcessor

        {

            protected float yuv;

 

            protected void ConvYuv(byte* rbyte* gbyte* b)

            {

                //rgb > yuv

                y = (0.299f * *r + 0.587f * *g + 0.114f * *b);

                u = 0.436f * (*b - y/ (1 - 0.144f+ 128;

                v = 0.615f * (*r - y/ (1 - 0.299f+ 128;

            }

 

            protected void ConvRgb(byte* rbyte* gbyte* b)

            {

                //yuv > rgb

                *r = Clip(y + 1.13983f * (v - 128));

                *g = Clip(y - 0.39465f * (u - 128- 0.58060f * (v - 128));

                *b = Clip(y + 2.03211f * (u - 128));

            }

 

        }

 

        //---- impl cls

 

        private unsafe class HVMImageProcessor : ImageProcessor

        {

            float[,] arrHorarrVer;

            private bool? hvm;

 

            public HVMImageProcessor(bool? hvm)

            {

                this.hvm = hvm;

            }

 

            public override Image ProcessImage(Image img)

            {

                var bmp = img.Make32bppRgbCopy();

                var lck = bmp.LockEntire32Rgb();

 

                arrHor = new float[lck.Width3];

                arrVer = new float[lck.Height3];

 

                ProcessImageInternal(lckComputeHV);

 

                ProcVal(arrHorlck.Height);

                ProcVal(arrVerlck.Width);

 

                switch (hvm)

                {

                    case true:

                        ProcessImageInternal(lckGenerateH);

                        break;

                    case false:

                        ProcessImageInternal(lckGenerateV);

                        break;

                    case null:

                        ProcessImageInternal(lckGenerateM);

                        break;

                    default:

                        throw new ArgumentException("hvm is not a Nullable<bool>?");

                }

 

 

                bmp.UnlockBits(lck);

 

                return bmp;

            }

 

            private static void ProcVal(float[,] arrint div)

            {

                var len1 = arr.GetLength(0);

                var len2 = arr.GetLength(1);

                for (int i = 0i < len1i++)

                {

                    for (int j = 0j < len2j++)

                    {

                        arr[ij/= div;

                    }

                }

            }

 

 

            private void ComputeHV(int xint ybyte* ptrRbyte* ptrGbyte* ptrB)

            {

                arrHor[x0+= *ptrB;

                arrHor[x1+= *ptrG;

                arrHor[x2+= *ptrR;

 

                arrVer[y0+= *ptrB;

                arrVer[y1+= *ptrG;

                arrVer[y2+= *ptrR;

            }

 

            private void GenerateH(int xint ybyte* ptrRbyte* ptrGbyte* ptrB)

            {

                *ptrB = (byte)arrHor[x0];

                *ptrG = (byte)arrHor[x1];

                *ptrR = (byte)arrHor[x2];

            }

 

            private void GenerateV(int xint ybyte* ptrRbyte* ptrGbyte* ptrB)

            {

                *ptrB = (byte)arrVer[y0];

                *ptrG = (byte)arrVer[y1];

                *ptrR = (byte)arrVer[y2];

            }

 

            private void GenerateM(int xint ybyte* ptrRbyte* ptrGbyte* ptrB)

            {

                *ptrB = (byte)((arrHor[x0+ arrVer[y0]) / 2.0);

                *ptrG = (byte)((arrHor[x1+ arrVer[y1]) / 2.0);

                *ptrR = (byte)((arrHor[x2+ arrVer[y2]) / 2.0);

            }

 

 

        }

 

        private unsafe class ChannelsImageProcessor : ImageProcessor

        {

            private int cr;

            private int cg;

            private int cb;

 

            public ChannelsImageProcessor(int crint cgint cb)

            {

                this.cr = cr;

                this.cg = cg;

                this.cb = cb;

            }

 

            public override Image ProcessImage(Image img)

            {

                var bmp = img.Make32bppRgbCopy();

                var lck = bmp.LockEntire32Rgb();

 

                ProcessImageInternal(lckProcessChannel);

 

                bmp.UnlockBits(lck);

                return bmp;

            }

 

            private void ProcessChannel(

                int xint ybyte* ptrRbyte* ptrGbyte* ptrB)

            {

                CalcChannel(ptrBptrBcb);

                CalcChannel(ptrGptrGcg);

                CalcChannel(ptrRptrRcr);

            }

 

        }

 

        private unsafe class EqPerImageProcessor : ImageProcessor

        {

            byte min_r = byte.MaxValue;

            byte min_g = byte.MaxValue;

            byte min_b = byte.MaxValue;

 

            byte max_r = byte.MinValue;

            byte max_g = byte.MinValue;

            byte max_b = byte.MinValue;

 

            int rng_r;

            int rng_g;

            int rng_b;

 

            public override Image ProcessImage(Image img)

            {

                var bmp = img.Make32bppRgbCopy();

                var lck = bmp.LockEntire32Rgb();

 

                ProcessImageInternal(lckCalcRng);

 

                rng_r = max_r - min_r;

                rng_g = max_g - min_g;

                rng_b = max_b - min_b;

 

                ProcessImageInternal(lckGenerateResult);

 

                bmp.UnlockBits(lck);

                return bmp;

            }

 

            private void CalcRng(int xint ybyte* rbyte* gbyte* b)

            {

                if (min_r > *rmin_r = *r;

                if (min_g > *gmin_g = *g;

                if (min_b > *bmin_b = *b;

                if (max_r < *rmax_r = *r;

                if (max_g < *gmax_g = *g;

                if (max_b < *bmax_b = *b;

            }

 

            private void GenerateResult(int xint ybyte* rbyte* gbyte* b)

            {

                *b = (byte)(((float)*b - min_b/ rng_b * 255);

                *g = (byte)(((float)*g - min_g/ rng_g * 255);

                *r = (byte)(((float)*r - min_r/ rng_r * 255);

            }

        }

 

        private unsafe class EqPerYuvImageProcessor : YuvImageProcessor

        {

            float min_y = float.MaxValue;

            float min_u = float.MaxValue;

            float min_v = float.MaxValue;

 

            float max_y = float.MinValue;

            float max_u = float.MinValue;

            float max_v = float.MinValue;

 

            float rng_y;

            float rng_u;

            float rng_v;

 

            public override Image ProcessImage(Image img)

            {

                var bmp = img.Make32bppRgbCopy();

                var lck = bmp.LockEntire32Rgb();

 

                ProcessImageInternal(lckCalcRng);

 

                rng_y = max_y - min_y;

                rng_u = max_u - min_u;

                rng_v = max_v - min_v;

 

                ProcessImageInternal(lckGenerateResult);

 

                bmp.UnlockBits(lck);

                return bmp;

            }

 

 

 

            private void CalcRng(int pxint pybyte* rbyte* gbyte* b)

            {

                ConvYuv(rgb);

 

                if (min_y > ymin_y = y;

                if (min_u > umin_u = u;

                if (min_v > vmin_v = v;

 

                if (max_y < ymax_y = y;

                if (max_u < umax_u = u;

                if (max_v < vmax_v = v;

            }

 

            private void GenerateResult(int pxint pybyte* rbyte* gbyte* b)

            {

                ConvYuv(rgb);

 

                //calc perccent

                y = (y - min_y/ rng_y * 255;

                //u = (u - min_u) / rng_u * 255;

                //v = (v - min_v) / rng_v * 255;

 

                ConvRgb(rgb);

            }

        }

 

        private unsafe class EqHisImageProcssor : ImageProcessor

        {

            int[] cdf_r = new int[256];

            int[] cdf_g = new int[256];

            int[] cdf_b = new int[256];

 

            int cdf_min_r = int.MaxValue;

            int cdf_min_g = int.MaxValue;

            int cdf_min_b = int.MaxValue;

 

            int totalPixel;

 

            public override Image ProcessImage(Image img)

            {

                var bmp = img.Make32bppRgbCopy();

                var lck = bmp.LockEntire32Rgb();

 

                totalPixel = lck.Width * lck.Height;

 

                ProcessImageInternal(lckCalcCdf);

 

                ProcCdf();

 

                ProcessImageInternal(lckGenerateResult);

 

                bmp.UnlockBits(lck);

                return bmp;

            }

 

            private void ProcCdf()

            {

                for (int i = 0i < 256i++)

                {

                    if (cdf_r[i!= 0)

                    {

                        for (int s = i - 1s >= 0s--)

                        {

                            if (cdf_r[s== 0)

                                continue;

 

                            cdf_r[i+= cdf_r[s];

                            break;

                        }

 

                        if (cdf_min_r > cdf_r[i])

                            cdf_min_r = cdf_r[i];

                    }

 

                    if (cdf_g[i!= 0)

                    {

                        for (int s = i - 1s >= 0s--)

                        {

                            if (cdf_g[s== 0)

                                continue;

 

                            cdf_g[i+= cdf_g[s];

                            break;

                        }

 

                        if (cdf_min_g > cdf_g[i])

                            cdf_min_g = cdf_g[i];

                    }

 

                    if (cdf_b[i!= 0)

                    {

                        for (int s = i - 1s >= 0s--)

                        {

                            if (cdf_b[s== 0)

                                continue;

 

                            cdf_b[i+= cdf_b[s];

                            break;

                        }

 

                        if (cdf_min_b > cdf_b[i])

                            cdf_min_b = cdf_b[i];

                    }

                }

            }

 

 

            private void CalcCdf(int pxint pybyte* rbyte* gbyte* b)

            {

                cdf_r[*r]++;

                cdf_g[*g]++;

                cdf_b[*b]++;

            }

 

            private void GenerateResult(int pxint pybyte* rbyte* gbyte* b)

            {

                *r = (byte)(((cdf_r[*r- cdf_min_r/ (totalPixel - 1.0)) * 255);

                *g = (byte)(((cdf_g[*g- cdf_min_g/ (totalPixel - 1.0)) * 255);

                *b = (byte)(((cdf_b[*b- cdf_min_b/ (totalPixel - 1.0)) * 255);

            }

 

        }

 

        private unsafe class EqHisYuvImageProcessor : YuvImageProcessor

        {

            byte* ptrLine;

            byte* ptrPix;

 

            int[] cdf_y = new int[256];

            int[] cdf_u = new int[256];

            int[] cdf_v = new int[256];

 

            int cdf_min_y = int.MaxValue;

            int cdf_min_u = int.MaxValue;

            int cdf_min_v = int.MaxValue;

 

            int totalPixel;

 

            public override Image ProcessImage(Image img)

            {

                var bmp = img.Make32bppRgbCopy();

                var lck = bmp.LockEntire32Rgb();

 

                totalPixel = lck.Width * lck.Height;

 

                ProcessImageInternal(lckCalcCdf);

 

                ProccCdf();

 

                ProcessImageInternal(lckGenerateResult);

 

 

                bmp.UnlockBits(lck);

                return bmp;

            }

 

            private void CalcCdf(int pxint pybyte* rbyte* gbyte* b)

            {

                ConvYuv(rgb);

 

                cdf_y[Clip(y)]++;

                cdf_u[Clip(u)]++;

                cdf_v[Clip(v)]++;

            }

 

            private void ProccCdf()

            {

                for (int i = 0i < 256i++)

                {

                    if (cdf_y[i!= 0)

                    {

                        for (int s = i - 1s >= 0s--)

                        {

                            if (cdf_y[s== 0)

                                continue;

 

                            cdf_y[i+= cdf_y[s];

                            break;

                        }

 

                        if (cdf_min_y > cdf_y[i])

                            cdf_min_y = cdf_y[i];

                    }

 

                    if (cdf_u[i!= 0)

                    {

                        for (int s = i - 1s >= 0s--)

                        {

                            if (cdf_u[s== 0)

                                continue;

 

                            cdf_u[i+= cdf_u[s];

                            break;

                        }

 

                        if (cdf_min_u > cdf_u[i])

                            cdf_min_u = cdf_u[i];

                    }

 

                    if (cdf_v[i!= 0)

                    {

                        for (int s = i - 1s >= 0s--)

                        {

                            if (cdf_v[s== 0)

                                continue;

 

                            cdf_v[i+= cdf_v[s];

                            break;

                        }

 

                        if (cdf_min_v > cdf_v[i])

                            cdf_min_v = cdf_v[i];

                    }

                }

            }

 

            private void GenerateResult(int pxint pybyte* rbyte* gbyte* b)

            {

                ConvYuv(rgb);

 

                //cdf - y

                y = (((cdf_y[(byte)y- cdf_min_y/ (totalPixel - 1.0f)) * 255);

                //uf = (((cdf_u[(byte)uf] - cdf_min_u) / (totalPixel - 1.0f)) * 255);

                //vf = (((cdf_v[(byte)vf] - cdf_min_v) / (totalPixel - 1.0f)) * 255);

 

                ConvRgb(rgb);

            }

 

        }

 

        private unsafe class BmImageProccessor : ImageProcessor

        {

            private bool andOr;

            private int xr;

            private int xg;

            private int xb;

 

            public BmImageProccessor(bool andOrint xrint xgint xb)

            {

                this.andOr = andOr;

                this.xr = xr;

                this.xg = xg;

                this.xb = xb;

            }

 

            public override Image ProcessImage(Image img)

            {

                var source = img.Make32bppRgbCopy();

                var result = new Bitmap(source.Widthsource.HeightPixelFormat.Format8bppIndexed);

 

                //init as bm

                var pat = result.Palette;

                pat.Entries[0= Color.Black;

                pat.Entries[1= Color.White;

                result.Palette = pat;

 

                var datSource = source.LockEntire32RgbR();

 

                var datResult = result.LockEntire(

                         ImageLockMode.WriteOnly

                        , PixelFormat.Format8bppIndexed

                    );

 

                byte* scanSource = (byte*)datSource.Scan0.ToPointer();

                byte* scanResult = (byte*)datResult.Scan0.ToPointer();

                byte* prtLineSourceprtLineResultptrPixSourceptrPixResult;

 

                for (int i = 0i < datSource.Height++i)

                {

                    prtLineSource = scanSource + (i * datSource.Stride);

                    prtLineResult = scanResult + (i * datResult.Stride);

 

                    for (int j = 0j < datSource.Width++j)

                    {

                        ptrPixSource = prtLineSource + (j * 4);

                        ptrPixResult = prtLineResult + (j);

 

                        bool flag;

 

                        if (andOr)

                            flag = ptrPixSource[0> xb

                                && ptrPixSource[1> xg

                                && ptrPixSource[2> xr;

                        else

                            flag = ptrPixSource[0> xb

                                || ptrPixSource[1> xg

                                || ptrPixSource[2> xr;

 

 

                        if (flag)

                            *ptrPixResult = 1;

                        else

                            *ptrPixResult = 0;

                    }

                }

 

                result.UnlockBits(datResult);

                source.UnlockBits(datSource);

 

                source.Dispose();

 

                return result;

            }

        }

 

 

        //---- pub func

 

        public static Image ProcBM(this Image imgbool andOrint xrgb)

        {

            return img.ProcBM(andOrxrgbxrgbxrgb);

        }

 

        public static Image ProcBM(this Image imgbool andOrint xrint xgint xb)

        {

            return new BmImageProccessor(andOrxrxgxb).ProcessImage(img);

        }

 

 

        public static Image ProcChannels(this Image imgint crgb)

        {

            return img.ProcChannels(crgbcrgbcrgb);

        }

 

        public static Image ProcChannels(this Image imgint crint cgint cb)

        {

            return new ChannelsImageProcessor(crcgcb).ProcessImage(img);

        }

 

 

        public static Image ProcEqPer(this Image img)

        {

            return new EqPerImageProcessor().ProcessImage(img);

        }

 

        public static Image ProcEqHis(this Image img)

        {

            return new EqHisImageProcssor().ProcessImage(img);

        }

 

 

        public static Image ProcEqPerYuv(this Image img)

        {

            return new EqPerYuvImageProcessor().ProcessImage(img);

        }

 

        public static Image ProcEqHisYuv(this Image img)

        {

            return new EqHisYuvImageProcessor().ProcessImage(img);

        }

 

 

 

        public static Image ProcHVM(this Image imgbool? hvm)

        {

            return new HVMImageProcessor(hvm).ProcessImage(img);

        }

    }

}

这个月总算赶上消灭0篇博文! 乂D

~

标签: 软件开发 C# 图像处理 算法

引用地址:

发表评论:

Powered by emlog 去你妹的备案 sitemap