遍历 UnsafeMutableRawPointer 图像数据。

3

我似乎无法理解在Swift中手动访问图像像素数据的方法。 我正在尝试从CGImage创建图像掩码,以便稍后可以在单独的图像上使用它。 我想识别特定值的所有像素,并将图像中的其他所有内容转换为黑白或透明度(目前并不重要)。 我正在尝试的代码如下:

    let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
    let contextWidth: Int = Int(snapshot.size.width)
    let contextHeight: Int = Int(snapshot.size.height)
    let bytesPerPixel: Int = 24
    let bitsPerComponent: Int = 8
    let bytesPerRow: Int = bytesPerPixel * contextWidth
    let bitmapInfo: CGBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipLast.rawValue)

    guard let context: CGContext = CGContext(data: nil, width: contextWidth, height: contextHeight, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else {
        print("Could not create CGContext")
        return
    }

    context.draw(maskCGImage, in: CGRect(x: 0, y: 0, width: contextWidth, height: contextHeight))
    guard let contextDataRaw: UnsafeMutableRawPointer = context.data else {
        print("Could not get UnsafeMutableRawPointer from CGContext")
        return
    }

    let contextData: UnsafeMutablePointer<UInt8> = contextDataRaw.bindMemory(to: UInt8.self, capacity: contextWidth * contextHeight)

    for row in 0..<contextHeight {
        for col in 0..<contextWidth {
            let offset = (col * contextHeight) + row
            let pixelArray = [contextData[offset], contextData[offset + 1], contextData[offset + 2]]
            if pixelArray == [120, 120, 120] {
                contextData[offset] = 0
                contextData[offset + 1] = 0
                contextData[offset + 2] = 0
            }

        }
    }

我尝试了各种行列排列方式,以确定正确的顺序,即let offset = (row * contextWidth) + collet offset = (col * contextHeight) + rowlet offset = ((row * contextWidth) + col) * 3let offset = ((row * contextWidth) + col) * 4
我的输出结果类似于这样(请记住,此图像应该看起来像一团随机颜色的斑点):

enter image description here

如我漂亮的小箭头所示,顶部的黑色样本是我编辑过的像素,这些像素确实应该变成黑色,然而所有其他灰色像素(例如箭头下面的像素)也应该变成黑色。它们的RGB值肯定是相同的120, 120, 120。
我知道问题在于我遍历数组的顺序,但似乎无法找出模式。另外需要注意的是,使用copy(maskingColorComponents:)不行,因为我想删除一些特定的颜色,而不是一系列颜色。
非常感谢您的帮助。提前致谢!

你试过调试你的代码了吗?很容易就能看出你是否正在按照你预期的在图像网格上进行足够次数的遍历。 - matt
我肯定尝试过。我试图访问特定像素(也是一系列像素),并将它们涂成黑色,以便在循环遍历图像时了解我击中的位置。我尝试了我能想到的每个行/列组合,但仍然无法获得正确的顺序。这真的非常令人沮丧。难道这些数据没有任何标准顺序吗?我不认为这应该那么难! - Michael
你显然做得很好,因为你已经正确地命中了左上角的所有像素。所以看起来你对一行的理解可能有点偏差。你正在说 for row in 0..<contextHeight 并且只是一次添加一个 row 到偏移量,但是在我看来,一个 row 跳跃的大小需要是一行中所有字节的大小。 - matt
@matt,你的想法非常正确。最终代码为let offset = (col * contextHeight) + (row * numComponents)。这样可以快速跳到正确的行,然后以4个字节为步长在该行中移动。如果你愿意将其写成答案,我可以将其标记为正确解决方案。 - Michael
也许这与问题无关,但是 bytesPerPixel 应该是 3 而不是 24 吗? - pbouf77
1个回答

1
你显然走在正确的轨道上,因为你已经准确地命中了左上角的所有像素。但是你没有一直往下扫描整张图片;显然你没有足够的行进行调查。所以问题可能仅仅是你对于“行”是什么的概念略微偏差。
for row in 0..<contextHeight {
    for col in 0..<contextWidth {
        let offset = (col * contextHeight) + row

似乎添加“row”实际上会将您带到该行。但是,“row”只是所需行的编号,而不是开始该行的字节;在我看来,一个行跳转的大小需要是一行中所有字节的大小。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接