我正在使用Swift为iOS构建这个 - 通过CoreImage或GPUImage,但如果我可以用Python或Node/JavaScript构建它,那也是有用的.随意抽象地回答,或者完全用不同的语言回答 - 我会接受任何大致描述我如何实现这个目标的答案.
考虑以下两个"图像"(我制作了两个3x3像素网格来表示两个图像,每个3x3像素,总共9个像素).
假设我使用着色器处理原始图像(左),该着色器改变某些像素但不是所有像素的颜色.右边的结果图像是相同的,但对于3个像素 - #2,#3和#6:
我试图找到一种方法来比较两个图像中的所有像素,并记录在过滤过程中未改变的像素的x,y位置.在这种情况下,当从左到右进行比较时,我需要知道#1,#4,#5,#7,#8和#9保持不变.
假设您之前和之后的图像大小相同,您需要做的就是遍历每个像素并比较它们可以用指针做的事情.我当然不认为这是最快的方法,但它应该工作(注意你可以用UInt32指针同时比较所有32位,但我正在按字节方式做,只是为了说明RGBA值在你需要的地方) .另请注意,由于Quartz是为Mac编写的,而且它使用的是笛卡尔坐标,而iOS和UIKit则没有,因此可能您的数据是颠倒的(镜像在X轴周围).你必须检查; 这取决于内部位图的表示方式.
func difference(leftImage: UIImage, rightImage: UIImage) { let width = Int(leftImage.size.width) let height = Int(leftImage.size.height) guard leftImage.size == rightImage.size else { return } if let cfData1:CFData = leftImage.cgImage?.dataProvider?.data, let l = CFDataGetBytePtr(cfData1), let cfData2:CFData = rightImage.cgImage?.dataProvider?.data, let r = CFDataGetBytePtr(cfData2) { let bytesPerpixel = 4 let firstPixel = 0 let lastPixel = (width * height - 1) * bytesPerpixel let range = stride(from: firstPixel, through: lastPixel, by: bytesPerpixel) for pixelAddress in range { if l.advanced(by: pixelAddress).pointee != r.advanced(by: pixelAddress).pointee || //Red l.advanced(by: pixelAddress + 1).pointee != r.advanced(by: pixelAddress + 1).pointee || //Green l.advanced(by: pixelAddress + 2).pointee != r.advanced(by: pixelAddress + 2).pointee || //Blue l.advanced(by: pixelAddress + 3).pointee != r.advanced(by: pixelAddress + 3).pointee { //Alpha print(pixelAddress) // do stuff here } } } }
如果您需要更快的方法,请编写一个着色器,该着色器将对每个像素进行增量并将结果写入纹理.输出中任何不清晰黑色(即0,0,0,0)的像素在图像之间是不同的.着色器不是我的专业领域所以我会留给别人写.此外,在一些架构上,读回昂贵的图形内存是昂贵的,所以你必须测试并看看这是否真的比在主内存中做得更好(也可能取决于图像大小,因为你必须分摊纹理的设置成本和着色器).