图像由排列在二维网格中的多个像素组成;行和列。图像的分辨率是行数和列数的乘积,行数表示图像的高度,列数表示图像的宽度。一张 1080x720 的图像总共有 777,600 个像素,每个像素都包含许多称为通道的颜色。数字图像通常由 3 个通道组成;红色、绿色和蓝色。灰度图像仅由一个通道组成;黑或白。每个像素由 8 位(~一个字节)表示,值范围为 0-255。每当对图像应用模糊等效果时,在幕后,它是一组直接应用于像素的数学运算,以实现所需的结果。
有多种技术用于模糊图像,其中一些是;
- 均值过滤器
- 高斯模糊
- 双边过滤器
应用过滤器的一种流行方法是内核卷积,其中一组数字(内核)通过图像的像素传递。内核是用于模糊和其他图像效果的小矩阵。核的大小一定是奇数,核的值越大,模糊效果越大。内核应用于图像中的每个像素,当前选定的像素位于内核的中心。内核中的每个值都与内核突出显示的矩阵范围内的各个像素值相乘,然后相加。中心像素值最终被这些操作的结果所取代。
模糊图像的本机方法
为了在android中实现均值滤波器,我们可以通过将图像转换为位图来获得像素,将内核应用于每个像素。我们将模糊应用到这个示例图像:
这是我的实现:
private suspend fun meanFilter(bitmap: Bitmap) {
val kernel = floatArrayOf(1 / 9f, 1 / 9f, 1 / 9f, 1 / 9f, 1 / 9f, 1 / 9f, 1 / 9f, 1 / 9f, 1 / 9f)
return withContext(Dispatchers.IO) {
val diameter = 3 // 3x3 matrix
val cols = bitmap.width
val rows = bitmap.height
val step = (diameter - 1) / 2
val imagePixels = IntArray(rows * cols)
val newImagePixels = IntArray(rows * cols)
bitmap.getPixels(imagePixels, 0, cols, 0, 0, cols, rows) // here we are assigning all pixel values to the IntArray so we can process the individual pixels via the kernel
for (i in 0 until cols) {
for (j in 0 until rows) {
val startCoord = Point(j - step, i - step)
val endCoord = Point(j + step, i + step)
val matrix = ArrayList<Int>()
for (_col in startCoord.y..endCoord.y) {
for (_row in startCoord.x..endCoord.x) {
if (_row < 0 || _row >= rows || _col < 0 || _col >= cols) {
//ignore pixels out of matrix bounds
matrix.add(0)
} else {
val pixel = imagePixels[_row * cols + _col]
matrix.add(pixel)
}
}
}
val sum = matrix.mapIndexed { index, value ->
val multiplier = kernel[index]
val alpha = value shr 24 and 0xFF
val red = ((value ushr 16 and 0xFF) * multiplier).toInt()
val green = ((value ushr 8 and 0xFF) * multiplier).toInt()
val blue = ((value and 0xFF) * multiplier).toInt()
((alpha) shl 24) or ((red) shl 16) or ((green) shl 8) or (blue)
}.sum()
newImagePixels[j * cols + i] = sum
}
}
Bitmap.createBitmap(newImagePixels, cols, rows, Bitmap.Config.ARGB_8888)
}
}
你会注意到我们在对像素值应用内核之前对它们进行了一些位移操作,这是因为每个像素都是由某些 8 位颜色值组成的,这些值在处理之前需要隔离,然后组合再次形成一个像素值。
使用 OpenCV 进行模糊处理
现在我们已经了解了模糊过滤器是如何在本地工作的,一个有用的图像处理库可以更快地完成很多这些特殊类型的操作,那就是 OpenCV。在这里,与我们最初编写的代码相比,只需几行代码就可以更