首页 > 解决方案 > 如何快速正确地从图像中提取数字数组?

问题描述

我正在尝试快速从 UIImage 中提取数字数组,但最后我只得到了一堆零,根本没有有用的信息。

这就是我编写的尝试完成此操作的代码。

var photo = UIImage(named: "myphoto.jpg")!

var withAlpha = true
var bytesPerPixels: Int = withAlpha ? 4 : 3

var width: Int = Int(photo.size.width)
var height: Int = Int(photo.size.height)

var bitsPerComponent: Int = 8
var bytesPerRow = bytesPerPixels * width
var totalPixels = (bytesPerPixels * width) * height

var alignment = MemoryLayout<UInt32>.alignment

var data = UnsafeMutableRawPointer.allocate(byteCount: totalPixels, alignment: alignment )

var bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue).rawValue


var colorSpace = CGColorSpaceCreateDeviceRGB()

let ctx = CGContext(data: data, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)


let bindedPointer: UnsafeMutablePointer<UInt32> = data.bindMemory(to: UInt32.self, capacity: totalPixels)

var pixels = UnsafeMutableBufferPointer.init(start: bindedPointer, count: totalPixels)


for p in pixels{
    print(p, Date())
}

最后,我尝试绑定 unsafeMutableRawPointer 以提取值但没有成功,我在这里可能缺少什么?

谢谢大家。

标签: swiftpixelcgcontextunsafe-pointers

解决方案


几点观察:

  • 您需要将图像绘制到上下文中。
  • 我还建议您不要创建必须手动管理的缓冲区,而是传递nil并让操作系统为您创建(和管理)该缓冲区。
  • 请注意,totalPixels应该只是width * height.
  • 您的代码假定scale图像的 是1。这并不总是一个有效的假设。我会抓住cgImage并使用它的widthand height
  • 即使您只有三个组件,您仍然需要使用每个像素 4 个字节。

因此:

guard 
    let photo = UIImage(named: "myphoto.jpg”),
    let cgImage = photo.cgImage
else { return }

let bytesPerPixels = 4

let width = cgImage.width
let height = cgImage.height

let bitsPerComponent: Int = 8
let bytesPerRow = bytesPerPixels * width
let totalPixels = width * height

let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue).rawValue

let colorSpace = CGColorSpaceCreateDeviceRGB()

guard
    let ctx = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo),
    let data = ctx.data
else { return }

ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))

let pointer = data.bindMemory(to: UInt32.self, capacity: totalPixels)

let pixels = UnsafeMutableBufferPointer(start: pointer, count: totalPixels)

for p in pixels {
    print(String(p, radix: 16), Date())
}

推荐阅读