C#Canny边缘检测算法

news/2024/7/21 5:51:56 标签: c#, 算法, 图像处理

在进行边沿检测前先对当前图像做相关操作,m_Bitmap是当前图像

Rectangle rect = new Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height);
BitmapData bmpData = m_Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, m_Bitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = m_Bitmap.Width * m_Bitmap.Height*3 ;
byte[] grayValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);

设置相关变量

				//得到阈值
                byte[] thresh = new byte[2];
                thresh[0] = Convert.ToByte(60);//根据实际需求改动
                thresh[1] = Convert.ToByte(25);//根据实际需求改动
                //得到均方差
                double sigema = 1.5;//根据实际需求改动
                double[] tempArray;
                double[] tempImage = new double[bytes];
                double[] grad = new double[bytes];
                byte[] aLable = new byte[bytes];
                double[] edgeMap = new double[bytes];
                double gradX, gradY, angle;

高斯模板半径

				//高斯模板半径=3sigema
                int rad = Convert.ToInt16(Math.Ceiling(3 * sigema));
                for (int i = 0; i < bytes; i++)
                {
                    tempImage[i] = Convert.ToDouble(grayValues[i]);
                }

//调用高斯平滑处理方法,在最下面会把该方法给出来

 gaussSmooth(tempImage, out tempArray, sigema);

//sobel一阶偏导求梯度幅值和方向

				for (int i = 0; i < m_Bitmap.Height; i++)
                {
                    for (int j = 0; j < m_Bitmap.Width; j++)
                    {
                        //水平方向梯度
                        gradX = tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] + 2 * tempArray[i * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] + tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] - tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] - 2 * tempArray[i * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] - tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)];

                        //垂直方向梯度
                        gradY = tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] + 2 * tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + j] + tempArray[((Math.Abs(i - 1)) % m_Bitmap.Height) * m_Bitmap.Width + ((j + 1) % m_Bitmap.Width)] - tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + ((Math.Abs(j - 1)) % m_Bitmap.Width)] - 2 * tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width + j]- tempArray[((i + 1) % m_Bitmap.Height) * m_Bitmap.Width+ ((j + 1) % m_Bitmap.Width)];

                        //梯度和
                        grad[i * m_Bitmap.Width + j] = Math.Sqrt(gradX * gradX + gradY * gradY);

                        //梯度方向(弧度)
                        
                        angle = Math.Atan2(gradY, gradX);

                        //四个方向量化
                        if ((angle >= -1.178097 && angle <= 1.178097) || angle >= 2.748894 || angle < -2.748894)
                        {
                            aLable[i * m_Bitmap.Width + j] = 0;
                        }
                        else if ((angle >= 0.392699 && angle < 1.178097) || (angle >= -2.748894 && angle < -1.963495))
                        {
                            aLable[i * m_Bitmap.Width + j] = 1;
                        }
                        else if ((angle >= -1.178097 && angle < -0.392699) || (angle >= 1.963495 && angle < 2.748894)) 
                        {
                            aLable[i * m_Bitmap.Width + j] = 2;
                        }
                        else
                        {
                            aLable[i * m_Bitmap.Width + j] = 3;
                        }

                    }
                }


//双阈值算法

				Array.Clear(grayValues, 0, bytes);
                for (int i = 0; i < m_Bitmap.Height ; i++)
                {
                    for (int j = 0; j < m_Bitmap.Width; j++)
                    {
                        if (edgeMap[i * m_Bitmap.Width + j]> thresh[0])
                        {
                            grayValues[i * m_Bitmap.Width + j] = 255;
                            //调用边缘的跟踪方法      
                            traceEdge(i, j, edgeMap, ref grayValues, thresh[1]);
                        }
                    }
                }

解锁m_Bitmap并在picturebox显示出来

				System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
                m_Bitmap.UnlockBits(bmpData);
                Invalidate();
                pictureBox1.Image = m_Bitmap;

在这个程序中涉及到两个方法
一个是高斯平滑处理方法:

		//高斯平滑处理方法
        //inputImage 输入图像
        // outputImage 输出图像
        //sigema 均方差
        private void gaussSmooth(double[]inputImage,out double[] outputImage,double sigema)
        {
            //方差
            double std2 = 2 * sigema * sigema;
            //半径=3sigema
            int radius = Convert.ToInt16(Math.Ceiling(3 * sigema));
            int filterWidth = 2 * radius + 1;
            double[] filter = new double[filterWidth];
            outputImage = new double[inputImage.Length];

            //限定输入的情况为方阵的情况下得到的图像的宽度和高度
            int length = Convert.ToInt16(Math.Sqrt(inputImage.Length));
            double[] tempImage = new double[inputImage.Length];

            double sum = 0;
            //产生一维高斯函数
            for (int i = 0; i < filterWidth; i++)
            {
                int xx = (i - radius) * (i - radius);
                filter[i] = Math.Exp(-xx / std2);
                sum += filter[i];
            }

            //归一化
            for (int i = 0; i < filterWidth; i++)
            {
                filter[i] = filter[i] / sum;
            }

            //水平方向滤波
            for (int i = 0; i < length; i++)
            {
                for (int j = 0; j < length; j++)
                {
                    double temp = 0;
                    for (int k = -radius; k <= radius; k++)
                    {
                        //循环拓展
                        int rem = (Math.Abs(j + k) % length);
                        //计算卷积和
                        temp += inputImage[i * length + rem] * filter[k + radius];
                    }
                    tempImage[i + length + j] = temp;
                }
            }

            //垂直方向滤波
            for (int j = 0; j < length; j++)
            {
                for (int i = 0; i < length; i++)
                {
                    double temp = 0;
                    for (int k = -radius ; k <=radius; k++)
                    {
                        //循环拓展
                        int rem = (Math.Abs(i + k) )% length;

                        //计算卷积和
                        temp += tempImage[rem * length + j] * filter[k + radius];
                    }
                    outputImage[i * length + j] = temp;
                }
            }
        }

另一个是边缘点跟踪方法:

		//边缘点跟踪方法
        //边缘跟踪,递归算法
        //k:图像纵坐标
        //l:图像横坐标
        //inputImage 梯度图像
        //outputImage 输出边缘图像
        //thrLow:低阈值
        private void traceEdge(int k,int l,double[]inputImage,ref byte[]outputImage,byte thrLow)
        {
            //8领域
            int[] kOffset = new int[] { 1, 1, 0, -1, -1, -1, 0, 1 };
            int[] lOffset = new int[] { 0, 1, 1, -1, 1, 0, -1, -1 };

            int kk, ll;
            
            for (int p = 0; p < 8; p++)
            {
                kk = k + kOffset[p];
                //循环拓展
                kk = Math.Abs(kk) % m_Bitmap.Height;

                ll = l + lOffset[p];
                //循环拓展
                ll = Math.Abs(ll) % m_Bitmap.Width;

                if (outputImage[ll * m_Bitmap.Width + kk] != 255) 
                {
                    if (inputImage[ll * m_Bitmap.Width + kk] > thrLow) 
                    {
                        outputImage[ll * m_Bitmap.Width + kk] = 255;

                        //递归调用
                        traceEdge(ll, kk, inputImage, ref outputImage, thrLow);
                    }
                }
            }
        }

http://www.niftyadmin.cn/n/1783355.html

相关文章

基于SmartGwt的分页组件

为什么80%的码农都做不了架构师&#xff1f;>>> 最近发现oschina不给我发每周精彩回顾了&#xff0c;才想起距离上次写东西已经有9个月了&#xff0c;于是狠狠的惭愧了一把。程序员光干活&#xff0c;不总结是不行的&#xff0c;于是便跟大家分享下下面这些开发体验…

继承同名静态成员处理方式

1.问题&#xff1a;继承中同名的静态成员在子类对象上如何进行访问&#xff1f; 2.静态成员和非静态成员出现同名&#xff0c;处理方式一致 访问子类同名成员 直接访问即可访问父类同名成员 需要加作用域 #include<iostream> using namespace std; #include<strin…

An error has occurred during report processing. (rsProcessingAborted) 对数据集“dsIteration”执行查询失败...

按照网上安装TFS2010的方法&#xff0c;装完后建立第一个项目&#xff0c;打开项目首页&#xff0c;报表无法显示&#xff0c;如下错误&#xff1a; 处理报表时出错。 (rsProcessingAborted) 对数据集“dsIteration”执行查询失败。 (rsErrorExecutingCommand)Team System 多维…

HDU 2802 找单词

找单词 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1398 Accepted Submission(s): 1017 Problem Description假设有x1个字母A&#xff0c; x2个字母B,..... x26个字母Z&#xff0c;同时假设字母A的价值为1&#x…

多继承用法

1.c允许一个类继承多个类 语法&#xff1a;class 子类&#xff1a;继承方式 父类1&#xff0c;继承方式 父类2... 多继承可能会引发父类中有同名成员出现&#xff0c;需要加作用域区分 c实际开发中不建议用多继承 #include<iostream> using namespace std; #include&…

你所不知道的水军:有人当借口有人当枪手

最近《王的盛宴》与《1942》吵的不可开交&#xff0c;双方都指责对方雇佣水军在时光网、豆瓣网等电影打分网站故意抹黑&#xff0c;而《王的盛宴》负责人也承认&#xff0c;“为了弥补恶意打低分&#xff0c;我们用了水军。”水军这个传说中的组织再一次出现在聚光灯下&#xf…

C#连接excel

把excel表格放到debug的文件夹里&#xff0c;这里用的excel文件格式是xls格式。 private void button1_Click(object sender, EventArgs e) {string filePath "D:ReadExcel\ReadExcel\bin\Debug\Car.xls";string strConn1 "ProviderMicrosoft.Jet.OLEDB.4.0;…

Wordpress XML-RPC协议说明

原文地址&#xff1a;http://codex.wordpress.org/XML-RPC_wp XML-RPC wp Note: This API is current as of the 2.7.1 release. Contents [hide]1 wp.getUsersBlogs 1.1 Parameters1.2 Return Values2 wp.getTags 2.1 Parameters2.2 Return Values3 wp.getCommentCount 3.1 Pa…