EmguCV学习(二)

来源:互联网 发布:围巾材质分类 知乎 编辑:程序博客网 时间:2024/06/05 06:55

(1)图像锐化处理


//此部分代码功能是锐化图像,本质上是 扫描图像并访问相邻像素//sharpened_pixel=5*current-left-right-up-downbyte saturateCast(double inValue){    if (inValue < 0)        return 0;    else if (inValue > 255)        return 255;    else        return (byte)inValue;}bool sharpen(Mat inImg,Mat outImg){    int nchannel = inImg.NumberOfChannels;    int nrows = inImg.Rows;    int ncols = inImg.Cols;    if(nchannel==1)    {        var tempImg=inImg.ToImage<Gray,byte>();        var tempImg2 = tempImg.Clone();        for(int i=1;i<nrows-1;++i)        {            for(int j=1;j<ncols-1;++j)            {                tempImg2.Data[i, j, 0] = saturateCast(5 * tempImg.Data[i, j, 0] - tempImg.Data[i - 1, j, 0] - tempImg.Data[i, j - 1, 0] -                tempImg2.Data[i + 1, j, 0] - tempImg.Data[i, j + 1, 0]);            }        }        for(int i=0;i<nrows;++i)        {            tempImg2.Data[i, 0, 0] = 0;            tempImg2.Data[i, ncols - 1, 0] = 0;        }        for(int j=0;j<ncols;++j)        {            tempImg2.Data[0, j, 0] = 0;            tempImg2.Data[nrows - 1, j, 0] = 0;        }        tempImg2.Mat.CopyTo(outImg);    }    else if(nchannel==3)    {        var tempImg = inImg.ToImage<Bgr, byte>();        var tempImg2 = tempImg.Clone();        for(int i=1;i<nrows-1;++i)        {            for(int j=1;j<ncols-1;++j)            {                for(int channel=0;channel<3;channel++)                {                    tempImg2.Data[i, j, channel] = saturateCast(5 * tempImg.Data[i, j, channel] - tempImg.Data[i - 1, j, channel] - tempImg.Data[i, j - 1, channel] -                        tempImg.Data[i + 1, j, channel] - tempImg.Data[i, j + 1, channel]);                }            }        }        for(int i=0;i<nrows;++i)        {            for(int channel=0;channel<3;channel++)            {                tempImg2.Data[i, 0, channel] = 0;                tempImg2.Data[i, ncols - 1, channel] = 0;            }        }        for(int j=0;j<ncols;++j)        {            for(int channel=0;channel<3;channel++)            {                tempImg2.Data[0, j, channel] = 0;                tempImg2.Data[nrows - 1, j, channel] = 0;            }        }        tempImg2.Mat.CopyTo(outImg);    }else    {        return false;    }    return true;}private void button27_Click(object sender, EventArgs e){    Mat inImage = new Mat();    Mat outImage = new Mat();    if (chapter1OFD.ShowDialog() == DialogResult.OK)        inImage = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);    if (inImage.IsEmpty)        return;    if (!sharpen(inImage, outImage))        return;    if (outImage.IsEmpty)        return;    imageBox7.Image = outImage;}private void button28_Click(object sender, EventArgs e){    if (chapter2Img.IsEmpty)        return;    Image<Gray, float> kernelI = new Image<Gray, float>(3, 3, new Gray(0));    kernelI.Data[1, 1, 0] = (float)5.0;    kernelI.Data[0, 1, 0] = (float)-1.0;    kernelI.Data[1, 0, 0] = (float)-1.0;    kernelI.Data[2, 1, 0] = (float)-1.0;    kernelI.Data[1, 2, 0] = (float)-1.0;    if(chapter2Img.NumberOfChannels==3)    {        var tempImg = chapter2Img.ToImage<Bgr, byte>();        Image<Gray,byte>[] results = tempImg.Split();        CvInvoke.Filter2D(results[0].Mat, results[0].Mat, kernelI.Mat, new Point(-1, -1));        CvInvoke.Filter2D(results[1].Mat, results[1].Mat, kernelI.Mat, new Point(-1, -1));        CvInvoke.Filter2D(results[2].Mat, results[2].Mat, kernelI.Mat, new Point(-1, -1));                         for(int i=0;i<tempImg.Rows;i++)            for(int j=0;j<tempImg.Cols;j++)            {                tempImg.Data[i, j, 0] = results[0].Data[i, j, 0];                tempImg.Data[i, j, 1] = results[1].Data[i, j, 0];                tempImg.Data[i, j, 2] = results[2].Data[i, j, 0];            }        imageBox7.Image = tempImg;    }    else if(chapter2Img.NumberOfChannels==1)    {        var tempImg = chapter2Img.ToImage<Gray, byte>();        CvInvoke.Filter2D(tempImg.Mat, tempImg.Mat, kernelI.Mat, new Point(-1, -1));        imageBox7.Image = tempImg;    }}


以上两部分按钮,一个用的是自定义的函数进行锐化处理,一个用到了filter2d函数





(2)检测图片中的颜色(本例中为浅蓝色),并显示检测结果,监测结果为二值图像,白色表示所检测的颜色部分,黑色表示非所检测颜色部分

Mat chapter3Img = new Mat();private void button29_Click(object sender, EventArgs e){    if(chapter1OFD.ShowDialog()==DialogResult.OK)    {        chapter3Img = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);        if (chapter3Img.IsEmpty)            return;    }    imageBox11.Image = chapter3Img;}private void button30_Click(object sender, EventArgs e){    if (chapter3Img.IsEmpty)        return;    ColorDetector cd = new ColorDetector();    cd.setTargetColor(230, 190, 130);    var result = cd.process(chapter3Img);    CvInvoke.NamedWindow("result", NamedWindowType.Normal);    CvInvoke.Imshow("result", result);}          }public class ColorDetector{    private int maxDist;    private MCvScalar targetColor;    private Mat result=new Mat();    private void setTarget(int b,int g,int r){     targetColor.V0 = b;    targetColor.V1 = g;    targetColor.V2 = r;}public void setTargetColor(byte blue,byte green,byte red){    setTarget(blue, green, red);}public void setTargetColor(Color c){    setTarget(c.B, c.G, c.R);}int getColorDistance(Color c1,Color c2){    return (int)Math.Sqrt(Math.Pow((c1.B - c2.B), 2) + Math.Pow((c1.G - c2.G), 2) + Math.Pow((c1.R - c2.R), 2));}int getDistanceToTargetColor(Color c){    Color tempC;    tempC = Color.FromArgb((int)targetColor.V2, (int)targetColor.V1, (int)targetColor.V0);    var ds=getColorDistance(c, tempC);    ////以下是采用opencv的norm函数进行计算,仅仅为了说明一下,故将其注释掉    //Mat temp = new Mat(3, 1, DepthType.Cv64F, 1);    //var tempImg = temp.ToImage<Gray,float>();    //tempImg.Data[0, 0, 0] = c.R - tempC.R;    //tempImg.Data[1, 0, 0] = c.G - tempC.G;    //tempImg.Data[2, 0, 0] = c.B - tempC.B;    //var opencvDs = CvInvoke.Norm(tempImg);    ////over    return (int)ds;}public ColorDetector(){    maxDist = 100;    setTarget(0, 0, 0);}void setColorDistanceThreshold(int distance){    if (distance < 0)        distance = 0;    maxDist = distance;}int getColorDistanceThreshold(){    return maxDist;}public Mat process(Mat inImg){    result.Create(inImg.Rows, inImg.Cols, DepthType.Cv8U, 1);    var tempImg = result.ToImage<Gray, byte>();    var tempImg2 = inImg.ToImage<Bgr, byte>();    for(int i=0;i<tempImg2.Rows;i++)        for(int j=0;j<tempImg2.Cols;j++)        {            if(getDistanceToTargetColor(Color.FromArgb(tempImg2.Data[i,j,2], tempImg2.Data[i, j, 1], tempImg2.Data[i, j, 0]))<maxDist)            {                tempImg.Data[i, j, 0] = 255;            }            else            {                tempImg.Data[i, j, 0] = 0;            }        }    tempImg.Mat.CopyTo(result);    return result;}





(3)HSV彩色空间,以及基于色调和饱和度的皮肤检测

private void button31_Click(object sender, EventArgs e)//HSV分离{    if (chapter3Img.IsEmpty)        return;    var tempImg = new Mat();    CvInvoke.CvtColor(chapter3Img, tempImg, ColorConversion.Bgr2Hsv);    if (tempImg.IsEmpty)        return;    var imgs = tempImg.Split();    imageBox12.Image = imgs[2];    imageBox14.Image = imgs[1];    imageBox13.Image = imgs[0];} private void button32_Click(object sender, EventArgs e){    if (chapter3Img.IsEmpty)        return;    var tempImg = new Mat();    CvInvoke.CvtColor(chapter3Img, tempImg, ColorConversion.Bgr2Hsv);    if (tempImg.IsEmpty)        return;    //var imgs = tempImg.Split();    //imgs[2].SetTo(new MCvScalar(255));    var img = tempImg.ToImage<Hsv, byte>();    for(int i=0;i<img.Rows;i++)        for(int j=0;j<img.Cols;j++)        {            img.Data[i, j, 2] = 255;//统一亮度        }    CvInvoke.CvtColor(img.Mat, tempImg, ColorConversion.Hsv2Bgr);    imageBox15.Image = tempImg;}//基于HSV彩色空间的皮肤识别void detectHScolor(Mat inImg,double minHue,double maxHue,double minSat,double maxSat,out Mat mask){    Mat HSVImg=new Mat();    CvInvoke.CvtColor(inImg, HSVImg, ColorConversion.Bgr2Hsv);    var hsvImgs = HSVImg.ToImage<Hsv, byte>().Split();    //色调掩码    Mat mask1 = new Mat();//小于maxHue    CvInvoke.Threshold(hsvImgs[0], mask1, maxHue, 255,ThresholdType.BinaryInv);    Mat mask2 = new Mat();//大于minHue    CvInvoke.Threshold(hsvImgs[0], mask2, minHue, 255, ThresholdType.Binary);    Mat hueMask = new Mat();//色调掩码    if (minHue < maxHue)        CvInvoke.BitwiseAnd(mask1, mask2, hueMask);    else        CvInvoke.BitwiseOr(mask1, mask2, hueMask);    //饱和度掩码    CvInvoke.Threshold(hsvImgs[1], mask1, maxSat, 255, ThresholdType.BinaryInv);    CvInvoke.Threshold(hsvImgs[1], mask2, minSat, 255, ThresholdType.Binary);    Mat satMask = new Mat();//饱和度掩码    CvInvoke.BitwiseAnd(mask1, mask2, satMask);    mask = new Mat();    CvInvoke.BitwiseAnd(hueMask, satMask, mask);    CvInvoke.NamedWindow("hue", NamedWindowType.Normal);    CvInvoke.NamedWindow("sat", NamedWindowType.Normal);    CvInvoke.Imshow("hue", hueMask);    CvInvoke.Imshow("sat", satMask);}private void button33_Click(object sender, EventArgs e){    if (chapter3Img.IsEmpty)        return;    Mat resultImg = new Mat();    detectHScolor(chapter3Img, 160, 10, 25, 166, out resultImg);    Mat detectedImg = chapter3Img.Clone();    detectedImg.SetTo(new MCvScalar(0, 0, 0));    chapter3Img.CopyTo(detectedImg, resultImg);    imageBox16.Image = detectedImg;}




(4)直方图显示(灰度图像)

不得不吐槽下,我是准备用

public static void CalcHist(IInputArray images, int[] channels, IInputArray mask, IOutputArray hist, int[] histSize, float[] ranges, bool accumulate);


这个函数来进行计算的,但不知道为何,运行的时候总是会提示错误,捣鼓半天也查不到解决方案。然后,发现了Emgucv3的一个叫做DenseHistogram的类,该类主要是用来生成1D的直方图数据,颇为好用,故此部分用该类进行相关计算。在进行显示时,我用到了两种方法:使用HistogramViewer和使用HistogramBox控件。以下为代码:

Mat chapter4Img = new Mat();private void button34_Click(object sender, EventArgs e){    if (chapter1OFD.ShowDialog() == DialogResult.OK)        chapter4Img = CvInvoke.Imread(chapter1OFD.FileName, LoadImageType.AnyColor | LoadImageType.AnyDepth);    if (chapter4Img.IsEmpty)        return;    imageBox17.Image = chapter4Img;}//以下是直方图计算类(灰度图像),内部使用DenseHistogram类class HisttoGram1D{    private int[] channels=new int[1];//使用的通道index    private int[] histSize= new int[1];//bin数量    private RangeF[] ranges=new RangeF[1];//像素值范围    private Mat mask=new Mat();//掩码    private Mat hist=new Mat();//得到的直方图数据    public HisttoGram1D()    {        channels[0] = 0;        histSize[0] = 256;        ranges[0] = new RangeF(0.0f, 255.1f);    }    public DenseHistogram getDenseHistogram(Mat inImg)    {        if (inImg.IsEmpty)        {            return null;        }        DenseHistogram dh = new DenseHistogram(histSize, ranges);        var imgs = inImg.ToImage<Gray, byte>().Split();        dh.Calculate(imgs, false, null);//计算直方图信息        return dh;    }}//直方图类定义overprivate void button35_Click(object sender, EventArgs e)//单通道图像{    Mat tempImg = new Mat();    HisttoGram1D ht1D = new HisttoGram1D();    if (chapter4Img.NumberOfChannels != 1)    {        CvInvoke.CvtColor(chapter4Img, tempImg, ColorConversion.Bgr2Gray);//彩色转灰度    }    else    {        tempImg = chapter4Img.Clone();    }    if (tempImg.IsEmpty)        return;    imageBox17.Image = tempImg;    //以下采用HistogramViewer类直接显示图像直方图    HistogramViewer hv = new HistogramViewer();    hv.Text = "单通道直方图";    hv.ShowInTaskbar = true;    hv.HistogramCtrl.GenerateHistograms(tempImg, 256);    hv.WindowState = FormWindowState.Normal;    hv.Show();    hv.Refresh();    //还有一种方式,直接使用HistogramViewer的静态函数,HistogramViewer.show(tempImg,256);也可以                 //以下使用HistogramBox控件进行直方图显示,需要配合DenseHistogram类    var dhData = ht1D.getDenseHistogram(tempImg);//获取DenseHistogram对象    //值得注意的是,此时dhData,也就是DenseHistogram类,虽然是继承的Mat类,但里面存储的已经是直方图信息    histogramBox2.ClearHistogram();    histogramBox2.AddHistogram("HistogramBox控件显示单通道直方图", Color.FromArgb(255, 0, 0), dhData, 256, new float[] { 0.0f, 255.0f });    histogramBox2.Refresh();     int[] testt = new int[256];    var ttt = tempImg.ToImage<Gray, byte>();    for(int i=0;i<tempImg.Rows;i++)        for(int j=0;j<tempImg.Cols;j++)        {            testt[ttt.Data[i, j, 0]]++;        }    int ii = 0;    for(int i=0;i<testt.Length;i++)    {        ii += testt[i];    }    double iii = 0.0;    for(int i=0;i<dhData.GetBinValues().Length;i++)    {        iii += dhData.GetBinValues()[i];    }    int iiii = 0;}


注意,以上有一句:

ranges[0] = new RangeF(0.0f, 255.1f);


如果将RangeF的范围设为0-255,最后得到的直方图会缺少像素值为255点的统计信息。原因我猜是rangeF的范围取值是[ min,max )方式吧。

这个问题把我困了n久。。。囧


接下来的小节我将重写一个直方图类,借助DenseHistogram,实现探测图像的通道(暂定为单通道和RGB彩色图像),并显示直方图。


(5)这一部分,可以读取无论是RGB三通道图像还是Gray单通道图像,并生成直方图的Mat数据并显示。

另外,还完成了点击“计算RGB直方图”这一按钮功能。

//定义函数,输入Mat图像,输出DenseHistogram对象DenseHistogram[] getDenseHistogramDataOfImage(Mat inImg)//这里的inImg深度暂定为byte{     DenseHistogram[] dh = new DenseHistogram[3] { new DenseHistogram(256, new RangeF(0f, 255.1f)), new DenseHistogram(256, new RangeF(0f, 255.1f)), new DenseHistogram(256, new RangeF(0f, 255.1f)) };    if (inImg.NumberOfChannels==3)    {        dh[0].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Bgr, byte>()[0] }, false, null);        dh[1].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Bgr, byte>()[1] }, false, null);        dh[2].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Bgr, byte>()[2] }, false, null);    }    else    {        dh[0].Calculate(new Image<Gray, byte>[] { inImg.ToImage<Gray, byte>()[0] }, false, null);        dh[1] = null;        dh[2] = null;    }    return dh;}private void button36_Click(object sender, EventArgs e){    if (chapter4Img.IsEmpty)        return;    var dhData = getDenseHistogramDataOfImage(chapter4Img);    histogramBox2.ClearHistogram();    if(chapter4Img.NumberOfChannels==3)    {        histogramBox2.AddHistogram("Blue直方图", Color.FromArgb(0, 0, 255), dhData[0], 256, new float[] { 0.0f, 255.0f });        histogramBox2.AddHistogram("Green直方图", Color.FromArgb(0, 255, 0), dhData[1], 256, new float[] { 0.0f, 255.0f });        histogramBox2.AddHistogram("Red直方图", Color.FromArgb(255, 0, 0), dhData[2], 256, new float[] { 0.0f, 255.0f });    }    else    {        histogramBox2.AddHistogram("直方图", Color.FromArgb(0, 0, 0), dhData[0], 256, new float[] { 0.0f, 255.0f });    }    histogramBox2.Refresh();}private Mat AddMultiHistograms(DenseHistogram[] dh)//此函数功能实现由输入的直方图数据生成Mat图像{    double maxValue = 0;    double minValue = 0;    if (dh[1] == null)//说明用于计算直方图的图像为单通道    {        var arrayData = dh[0].GetBinValues();        maxValue = arrayData.Max();        minValue = arrayData.Min();        for (int i = 0; i < arrayData.Length; i++)        {            arrayData[i] = (int)((arrayData[i] - minValue) / (maxValue - minValue) * 400.0);        }        var hist = new Image<Gray, byte>(512, 512, new Gray(255));        Point p1 = new Point();        Point p2 = new Point();        p1.X = 0;        p1.Y = 512-(int)arrayData[0];        for (int i = 1; i < arrayData.Length; i++)        {            p2.X = i*2;            p2.Y = 512-(int)arrayData[i];            CvInvoke.Line(hist, p1, p2, new MCvScalar(0),3);            p1.X = p2.X;            p1.Y = p2.Y;        }        return hist.Mat;    }    else    {        List<float[]> arrayData = new List<float[]> { dh[0].GetBinValues(), dh[1].GetBinValues(), dh[2].GetBinValues() };//颜色顺序BGR        maxValue = Math.Max(Math.Max(dh[0].GetBinValues().Max(), dh[1].GetBinValues().Max()), dh[2].GetBinValues().Max());        minValue=Math.Min(Math.Min(dh[0].GetBinValues().Min(), dh[1].GetBinValues().Min()), dh[2].GetBinValues().Min());        for(int index=0;index<arrayData.Count;index++)        {            for(int i=0;i<arrayData[index].Length;i++)            {                arrayData[index][i] = (float)((arrayData[index][i] - minValue) / (maxValue - minValue)*400.0);            }        }        var hist = new Image<Bgr, byte>(512, 512, new Bgr(255, 255, 255));//初始化图像        Point p1 = new Point();        Point p2 = new Point();        var colors = new MCvScalar[3] { new MCvScalar(255, 0, 0), new MCvScalar(0, 255, 0), new MCvScalar(0, 0, 255) };        for(int index=0;index<arrayData.Count;index++)        {            p1.X = 0;            p1.Y = 512 - (int)arrayData[index][0];            for(int i=1;i<arrayData[index].Length;i++)            {                p2.X = i*2;                p2.Y = 512 - (int)arrayData[index][i];                CvInvoke.Line(hist, p1, p2, colors[index], 3);                p1.X = p2.X;                p1.Y = p2.Y;            }        }        return hist.Mat;    }}private void button37_Click(object sender, EventArgs e){    if (chapter4Img.IsEmpty)        return;    var dhData = getDenseHistogramDataOfImage(chapter4Img);    var histMat = AddMultiHistograms(dhData);    imageBox18.Image = histMat;}





(6)基于查找表的颜色反转

无论是彩色还是单通道都可以哈

//利用查找表反转灰度图像private void button38_Click(object sender, EventArgs e){    if (chapter4Img.IsEmpty)        return;    Mat lut = new Mat(1, 256, DepthType.Cv8U, 1);    byte[] data = new byte[256];    for(int i=0;i<data.Length;i++)    {        data[i] = (byte)(256 - i);    }    lut.SetTo(data);    Mat resultImg = new Mat();    CvInvoke.LUT(chapter4Img, lut, resultImg);    imageBox17.Image = resultImg;}


?






0 0
原创粉丝点击