什么是图像的边缘? 图像的边缘是图像最基本的特征之一。所谓边缘(或边沿)是指周围像素灰度有跳跃性变化或“屋顶”变化的那些像素的集合。边缘是图像局部强度变化最明显的地方,它主要存在于目标与目标、目标与背景、区域与区域之间,因此它是图像分割依赖的重要特征。从本质上说,图像边缘是图像局部特性不连续性(灰度突变、颜色突变、纹理结构突变等)的反应,它标志着一个区域的终结和另一个区域的开始。 检测出的边缘并不等同于实际目标的真实边缘。由于图像数据是二维的,而实际物体是三维的,从三维到二维的投影必然会造成信息的丢失,再加上成像过程中的光照不均和噪声等因素的影响,使得有边缘的地方不一定能被检测出来,而检测出的边缘也不一定代表实际边缘。 图像的边缘有方向和幅度两个属性,沿边缘方向像素变化平缓,垂直于边缘方向像素变化剧烈。边缘上的这种变化可以用微分算子检测出来,通常用一阶或两阶导数来检测边缘。一阶导数认为最大值对应边缘位置,而二阶导数则以过零点对应边缘位置。 由于图像是离散的信号,我们可以用临近的两个像素差值来表示像素灰度值函数的导数,如下: 这种X轴方向求导方式对应于滤波器为[1, -1],对于Y轴方向则是[1, -1]的转置矩阵。 但是这种求导方式的计算结果最接近于两个像素中间位置的梯度,而两个像素之间是不存在像素的,因此,我们应该选取像素点的前后像素的差值来进行计算,如下: 此时,对应的X轴方向的滤波器为[0.5, 0, -0.5],对应的Y轴方向的滤波器则是其转置矩阵。根据这种方式,我们也可以得到计算45度方向的梯度对应的滤波器。 图像的边缘有可能是由高像素值变为低像素值,也有可能是由低像素值变成高像素值,通过卷积计算得到的正数值表示需要像素值突然由低变高,得到的负数值表示像素值由高到低,这两种都是图像的边缘,因此为了在图像中同时表示出这两种边缘信息,需要将计算的结果求取绝对值。 该函数可以求取矩阵中所有数据的绝对值。函数前两个参数分别为输入、输出矩阵,两个参数可以是相同的变量。函数第三个和第四个参数为对绝对值的缩放和原始数据上的偏移。函数的计算原理如式: https://github.com/onlyloveyd/LearningAndroidOpenCV 回复【计算机视觉】获取计算机视觉相关必备学习资料
边缘检测
0.50000000−0.5
00−0.50000.500API
图像卷积
public static void filter2D(Mat src, Mat dst, int ddepth, Mat kernel, Point anchor, double delta, int borderType)
绝对值
public static void convertScaleAbs(Mat src, Mat dst, double alpha, double beta)
dst(I)=saturate_cast<uchar>(∣src(I)∗alpha+beta∣)操作
/** * 边缘检测 * author: yidong * 2020/5/2 */ class EdgeDetectionActivity : AppCompatActivity() { private lateinit var mBinding: ActivityEdgeDetectionBinding private lateinit var mRgb: Mat override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = DataBindingUtil.setContentView(this, R.layout.activity_edge_detection) val bgr = Utils.loadResource(this, R.drawable.lena) mRgb = Mat() Imgproc.cvtColor(bgr, mRgb, Imgproc.COLOR_BGR2RGB) showMat(mBinding.ivLena, mRgb) } private fun showMat(view: ImageView, source: Mat) { val bitmap = Bitmap.createBitmap(source.width(), source.height(), Bitmap.Config.ARGB_8888) bitmap.density = 360 Utils.matToBitmap(source, bitmap) view.setImageBitmap(bitmap) } override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.menu_edge_detection, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.edge_detection_x -> { edgeDetectionX() } R.id.edge_detection_y -> { edgeDetectionY() } R.id.edge_detection_x_y -> { edgeDetectionXAndY() } R.id.edge_detection_xy -> { edgeDetectionXY() } R.id.edge_detection_yx -> { edgeDetectionYX() } } return true } private fun edgeDetectionX() { title = "X轴方向边缘检测" // X轴方向边缘检测 val kernelX = Mat(1, 3, CvType.CV_16S) val arrayX = shortArrayOf(-1, 0, 1) kernelX.put(0, 0, arrayX) val resultKernelX = Mat() Imgproc.filter2D(mRgb, resultKernelX, CvType.CV_16S, kernelX) Core.convertScaleAbs(resultKernelX, resultKernelX) showMat(mBinding.ivResult, resultKernelX) kernelX.release() resultKernelX.release() } private fun edgeDetectionY() { title = "Y轴方向边缘检测" // Y轴方向边缘检测 val kernelY = Mat(3, 1, CvType.CV_16S) val arrayY = shortArrayOf(-1, 0, 1) kernelY.put(0, 0, arrayY) val resultKernelY = Mat() Imgproc.filter2D(mRgb, resultKernelY, CvType.CV_16S, kernelY) Core.convertScaleAbs(resultKernelY, resultKernelY) showMat(mBinding.ivResult, resultKernelY) kernelY.release() resultKernelY.release() } private fun edgeDetectionXAndY() { title = "X和Y轴方向边缘检测" // X轴方向边缘检测 val kernelX = Mat(1, 3, CvType.CV_16S) val arrayX = shortArrayOf(-1, 0, 1) kernelX.put(0, 0, arrayX) val resultKernelX = Mat() Imgproc.filter2D(mRgb, resultKernelX, CvType.CV_16S, kernelX) Core.convertScaleAbs(resultKernelX, resultKernelX) // Y轴方向边缘检测 val kernelY = Mat(3, 1, CvType.CV_16S) val arrayY = shortArrayOf(-1, 0, 1) kernelY.put(0, 0, arrayY) val resultKernelY = Mat() Imgproc.filter2D(mRgb, resultKernelY, CvType.CV_16S, kernelY) Core.convertScaleAbs(resultKernelY, resultKernelY) // X,Y轴方向合并 val resultXY = Mat() Core.add(resultKernelX, resultKernelY, resultXY) showMat(mBinding.ivResult, resultXY) kernelX.release() resultKernelX.release() kernelY.release() resultKernelY.release() resultXY.release() } private fun edgeDetectionXY() { title = "由左上到右下方向边缘检测" //由左上到右下方向边缘检测 val kernelXY = Mat(2, 2, CvType.CV_16S) val arrayXY = shortArrayOf(1, 0, 0, -1) kernelXY.put(0, 0, arrayXY) val resultKernelXY = Mat() Imgproc.filter2D(mRgb, resultKernelXY, CvType.CV_16S, kernelXY) Core.convertScaleAbs(resultKernelXY, resultKernelXY) showMat(mBinding.ivResult, resultKernelXY) kernelXY.release() resultKernelXY.release() } private fun edgeDetectionYX() { title = "由右上到左下方向边缘检测" //由右上到左下方向边缘检测 val kernelYX = Mat(2, 2, CvType.CV_16S) val arrayYX = shortArrayOf(0, -1, 1, 0) kernelYX.put(0, 0, arrayYX) val resultKernelYX = Mat() Imgproc.filter2D(mRgb, resultKernelYX, CvType.CV_16S, kernelYX) Core.convertScaleAbs(resultKernelYX, resultKernelYX) showMat(mBinding.ivResult, resultKernelYX) kernelYX.release() resultKernelYX.release() } }
效果
源码
扫码关注,持续更新
回复【Android】获取Android,Kotlin必备学习资料
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算