Nat*_*ega 3 python base64 opencv numpy swift
正如标题所暗示的,我在一些 UIImage 颜色空间转换方面遇到了一些麻烦。TL;DR 版本是我需要一种将 BGR 格式的 UIIMage 转换为 RGB 的方法。
这是我的应用程序中的事件流:
此时显示的 UIImage 为 BGR 格式。我最好的猜测是第 4 步出了问题,因为在那之前图像是 RGB 格式的(我已将其写入文件并进行了检查)。我已将代码添加到下面的第 4 步,仅供参考。我正在积极寻求更改 UIImage 客户端的色彩空间,但我不反对解决服务器端的问题。任何一种解决方案都可以。
第 2 步:将 UIIMage 转换为 base64 字符串
let imageData: Data = UIImageJPEGRepresentation(map.image,0.95)!
let base64EnCodedStr: String = imageData.base64EncodedString()
Run Code Online (Sandbox Code Playgroud)
第 3 步:将 base64 字符串转换为 PIL 图像
import io
import cv2
import base64
import numpy as np
from PIL import Image
# Take in base64 string and return PIL image
def stringToImage(base64_string):
imgdata = base64.b64decode(base64_string)
return Image.open(io.BytesIO(imgdata))
Run Code Online (Sandbox Code Playgroud)
第 4 步:将图像(numpy 数组)转换回 base64 字符串
# Convert a numpyArray into a base64 string in JPEG format
def imageToString(npArray):
# convert array to PIL Image
newImage = Image.fromarray(npArray.astype('uint8'), 'RGB')
# convert to JPEG format
file = io.BytesIO()
newImage.save(file, format="JPEG")
# reset file pointer to start
file.seek(0)
img_bytes = file.read()
# encode data
encodedData = base64.b64encode(img_bytes)
return encodedData.decode('ascii')
Run Code Online (Sandbox Code Playgroud)
如前所述,我可以在两个位置进行转换:服务器端或客户端。感谢对这个问题的回答,我能够为这两种情况找到解决方案。
参考步骤 4 中的代码,将该函数中的第一行更改为以下内容:
# convert array to PIL Image
newImage = Image.fromarray( npArray[...,[2,1,0]] ) # swap color channels which converts BGR -> RGB
Run Code Online (Sandbox Code Playgroud)
请参阅@dfd 的解决方案。它写得很好,效果很好。这是我在我的应用程序中测试过的稍微调整的版本(使用 swift 4)。
let data = NSData(base64Encoded: base64String, options: .ignoreUnknownCharacters)
let uiInput = UIImage(data: data! as Data)
let ciInput = CIImage(image: uiInput!)
let ctx = CIContext(options: nil)
let swapKernel = CIColorKernel( string:
"kernel vec4 swapRedAndGreenAmount(__sample s) {" +
"return s.bgra;" +
"}"
)
let ciOutput = swapKernel?.apply(withExtent: (ciInput?.extent)!, arguments: [ciInput as Any])
let cgImage = ctx.createCGImage(ciOutput!, from: (ciInput?.extent)!)
let rgbOutput = UIImage(cgImage: cgImage!)
Run Code Online (Sandbox Code Playgroud)
这是一个非常简单的 CIKernel 来交换东西:
kernel vec4 swapRedAndGreenAmount(__sample s) {
return s.bgra;
}
Run Code Online (Sandbox Code Playgroud)
这是使用它的 Swift 代码:
let uiInput = UIImage(named: "myImage")
let ciInput = CIImage(image: uiInput!)
let ctx = CIContext(options: nil)
let swapKernel = CIColorKernel( source:
"kernel vec4 swapRedAndGreenAmount(__sample s) {" +
"return s.bgra;" +
"}"
)
let ciOutput = swapKernel?.apply(extent: (ciInput?.extent)!, arguments: [ciInput as Any])
let cgImage = ctx.createCGImage(ciOutput!, from: (ciInput?.extent)!)
let uiOutput = UIImage(cgImage: cgImage!)
Run Code Online (Sandbox Code Playgroud)
请注意以下几点:
CIContext创建CGImagea UIImage。您可以删除此步骤并直接从 aCIImage转到 a UIImage。解释:
使用 CoreImage“内核”代码(在 iOS 11 之前只能是 GLSL 代码的子集),我编写了一个简单的方法CIColorKernel,它采用像素的 RGB 值并将像素颜色作为 GRB 返回。
ACIColorKernel被优化为一次处理单个像素,而无法访问它周围的像素。与此不同的是, aCIWarpKernel被优化为基于它周围的像素“扭曲”一个像素。这两个(或多或少)都是 a 的优化子类,在CIKerneliOS 11 和 Metal Performance Shaders 之前,它是最接近您openGL在CoreImage.
最终编辑:
此解决方案的作用是使用 CoreImage 逐个交换像素的 RGB。它很快,因为它使用 GPU,看似很快(因为模拟器不会给你任何接近设备实时性能的东西),而且很简单(因为它把东西从 RGB 交换到 BGR)。
执行此操作的实际代码很简单。希望它可以作为那些想要使用 CoreImage 做更大的“幕后”事情的人的开始。
编辑(2021 年 2 月 25 日):
从 WWDC 2019 开始,Apple 已弃用 openGL,特别GLKit是支持MetalKit. 对于像这样的颜色内核,转换此代码相当简单。不过,Warp 内核稍微复杂一些。
至于Apple什么时候会“杀死”OpenGL 很难说。我们都知道总有一天UIKit会被弃用,但是(现在显示我的年龄)它可能不会在我有生之年。天啊。
| 归档时间: |
|
| 查看次数: |
2220 次 |
| 最近记录: |