本文字数:2323 字
预计阅读时间:20 分钟
本篇介绍的是图像的二值图,讲解由彩色图>灰度图>二值图的转换过程和基于Swift实现的Mac工具QHBinimageMan¹。让读者进一步了解图像的像素和像素间处理的图像技术。类似之前的《iOS隐形水印之LSB实现》,也是对图像的RGB图像进行读取&修改。
工具
QHBinimageMan二值图生成工具。可进行阈值、分辨率缩放的控制生成二值图(项目工程相对简单,可以参考)。
彩色图
在MacOS / iOS下,可分别通过NSImage / UIImage转换CVPixelBuffer来读取RGB转换值,此步骤是由CoreVideo框架来解码图片。
// 创建 CVPixelBuffer
var temp_pb: CVPixelBuffer?
let r = CVPixelBufferCreate(kCFAllocatorDefault, w, h, kCVPixelFormatType_32ARGB, opt, &temp_pb);
// 读取原数据
let pb_data = CVPixelBufferGetBaseAddress(pb)
灰色图
灰度是指红色、绿色和蓝色分量在RGB空间的值是一样。使用彩色图均先转换为灰度图,方便分离前后景,从而生成二值图。
彩色转灰度:采用BT.709色域来转换,这其实就是yuv的亮度值y。
// rgb 转换 y 值
let red = Float(data[offset+1]) * 0.2126
let green = Float(data[offset+2]) * 0.7152
let blue = Float(data[offset+3]) * 0.0722
let v = UInt8(red + green + blue)
// rgb 设置成 y 值
data[offset+1] = v
data[offset+2] = v
data[offset+3] = v
直方图
直方图可以更好地可视化来选择二值图的阈值。这里也可以说明为什么需要使用灰度图,而不是彩色图直接转换二值图,因为彩色图的直方图有RGB三个,没有灰度图的方便确认阈值。
阈值化:
❝In many vision applications, it is useful to be able to separate out the regions of the image corresponding to objects in which we are interested, from the regions of the image that correspond to background. Thresholding often provides an easy and convenient way to perform this segmentation on the basis of the different intensities or colors in the foreground and background regions of an image.
In addition, it is often useful to be able to see what areas of an image consist of pixels whose values lie within a specified range, or band of intensities (or colors). Thresholding can be used for this as well.
工具生成的是灰度图的直方图,分为16个单位的灰度颜色强度的先前来展示:
// 分块
var i = 0
for p in ps {
pss[i/16] += p
i += 1
}
i = 0
for p in pss {
// 计算平均值
pss[i] = p/16
// 最高颜色强度值
maxP = max(maxP, pss[i])
i += 1
}
可以看出此示例灰度图的颜色强度主要分布在头部、尾部和中间,即分别对应黑(0),白(256)和灰色(128)。
二值图
二值图通常就是指黑白图,像素只有两个值,分别是(1或255)和0。
本工具将在阈值区间内的颜色强度记为 1,不符合的记为 0。明显看出示例图片的黑色点,即直方图的 0 - 16 区域是图片的前景边线,所以可以选择(0, 20)的区域作为阈值区域。
let v = data[offset+1]
// 阈值区间筛选 & 记录
if v > minbin && v < maxbin {
matrixLine += "1"
}
else {
matrixLine += "0"
}
阈值决定了要显示的部分,如下是选择不同阈值的效果图。可以明显看出它们包含 ”1“ 的个数是不同的,即细节的差异。建议将工具生成的二值图,复制到 Sublime Text 等工具看是 0-1 对齐效果更佳。
(0,20) | (0,120) |
降分辨率
可以先看看,一张图片裁剪后竟然可重组为四张!_分辨率-搜狐新闻² 生动的演示了降分辨率。
而图片经过多次剪切,仍然可以看出原画面。工具参考此来降分辨率,通过隔行和隔列进行裁剪来缩放。
// 缩放比例
let ss = max(ratio, 1)
// 满足的行列进行裁剪记录
for y in 0..<h {
if y%ss == 0 {
for x in 0..<w {
if x%ss == 0 {
// ...
}
}
}
}
其实上面显示的直方图&二值图都是使用了已经降分辨率的图像。因为不降分辨率的话,其像素值太大(宽高太大),很难预览全整张图。不降分辨率的话,其细节更全,所以降分辨率会相对模糊了图片。
应用
直播间的送礼,一般礼物都分高低等级。高等级礼物的赠送都会有很炫的礼物动画,而低等级的只是图片。那么对于低等级礼物的连送,常用的就是使用组合动画,就是将多个小礼物拼成一个图形的效果。
用硬代码编写,费时费力,且不容易更新。那么此时就可以使用二值图。
思路:
将二值图的1用小礼物图片代替
通过初始随机的小礼物图标位置
动画移动到指定二值图的1位置
可以降低更小的分辨率,因为动画其实只需简单的组合轮廓。这样即可以显示小图片,且不会显得过于密集,能大致看出图形即可到达效果。二值图还方便修改,只需要手动直接修改0-1即可。
App上组合动画的效果如下:
链接:
1. https://gitee.com/chenqihui/qhbinimage-man
2. https://www.sohu.com/a/288969657_472787