我正在使用 Metal Core Image 著色器渲染視頻幀。我的要求之一是能夠從 CIImage 中選擇一種特定的顏色(以及用戶選擇的附近范圍),將該顏色保留在輸出中,并將其他所有顏色變為黑白(顏色飛濺)。但我對適用于在各種色彩空間(包括 10 位 HDR)中拍攝的視頻的正確方法感到困惑:
第一項作業是在任何給定像素位置從 CIImage 中提取顏色值。據我了解,這可以使用以下 API 提取:
func render(_ image: CIImage, toBitmap data: UnsafeMutableRawPointer, rowBytes: Int, bounds: CGRect, format: CIFormat, colorSpace: CGColorSpace?)
API 表示將 NULL 傳遞給 colorSpace 將導致輸出位于 ciContext outputColorSpace 中。考慮到 8 位和 10 位輸入影像的可能性,目前尚不清楚如何正確使用此 API 在給定像素位置提取準確的顏色?
- 提取值后,下一個問題是如何將值傳遞給 Metal Core Image 著色器?著色器使用依賴于ciContext的 workingcolorSpace 的標準化顏色范圍。我是否需要使用應該傳遞給著色器的顏色創建一維紋理,或者有更好的方法?
uj5u.com熱心網友回復:
根據您的評論,這是另一種選擇:
您可以使用背景關系的作業顏色空間將像素值讀取為浮點數。通過使用浮點值,您可以確保輸入的位深度無關緊要,并且可以正確表示擴展的顏色值。因此,例如,BT.2020 中的 100% 紅色將導致 sRGB 值的擴展。(1.2483, -0.3880, -0.1434)
要讀取該值,您可以使用我們的小型幫助程式庫CoreImageExtensions(或查看實作以了解如何使用render獲取浮點值):
let pixelColor = context.readFloat32PixelValue(from: image, at: coordinate, colorSpace: context.workingColorSpace)
// you can convert that to CIVector, which can be passed to a kernel
let vectorValue = CIVector(x: pixelColor.r, y: pixelColor.g, ...)
在您的 Metal 內核中,您可以使用float4該顏色的輸入引數。
只要您workingColorSpace對背景關系使用相同的顏色值,您就可以在以后的渲染呼叫中存盤和使用顏色值。
uj5u.com熱心網友回復:
我認為您可以實作這一點,而無需擔心色彩空間,甚至無需中間渲染步驟(這應該會大大提高性能)。
您可以簡單地將影像裁剪為包含特定顏色的 1x1 像素方形影像,并使影像在所有方向上幾乎無限延伸。然后,您可以將該影像傳遞到您的下一個內核并在任何地方對其進行采樣以檢索顏色值(在與以前相同的顏色空間中)。
let pixelCoordinate: CGPoint // the coordinate of the pixel that contains the color
// crop down to a single pixel
let colorPixel = inputImage.cropped(to: CGRect(origin: pixelCoordinate, size: CGSize(width: 1, height: 1))
// make the pixel extent infinite
let colorImage = colorPixel.clampedToExtent()
// simply pass it to your kernel
myKernel.apply(..., arguments: [colorImage, ...])
在 Metal 內核代碼中,您可以簡單地通過sampler(或sample_t在顏色內核中)訪問它并像這樣對其進行采樣:
// you can sample at any coord since the image contains the single color everywhere
float4 pickedColor = colorImage.sample(colorImage.coord());
uj5u.com熱心網友回復:
要從 CIImage 讀取“原始”顏色值,用于將像素渲染到位圖的 CIContext 需要同時創建workingColorSpace并outputColorSpace設定為NSNull(). 那么就不會有色彩空間轉換,你也不必擔心色彩空間:
let context = CIContext(options: [.workingColorSpace: NSNull(), .outputColorSpace: NSNull()])
然后,在將像素渲染為位圖時,指定最高精度的顏色格式CIFormat.RGBAf,以確保您沒有剪裁任何值。并nil用于colorSpace引數。正如第一個答案所建議的那樣,您將獲得每個像素 4 個 Float32 值,這些值可以傳遞給 CIVector 中的著色器。
但是,您可以做另一件事,借用第二個答案中的裁剪和鉗制思想。
- 使用該答案中建議的方法創建一個僅包含所選顏色的無限影像。
- 將該影像裁剪到框架的范圍
- 使用
CIColorAbsoluteDifference一個輸入是原始幀,另一個是這個統一的彩色影像。 - 該過濾器的輸出將使與所選顏色完全匹配的所有像素回傳,并且其他像素都不會是黑色,因為此過濾器計算顏色之間的絕對差異,并且只有顏色完全相同的像素才會產生(0 ,0,0) 輸出。
- 將該影像傳遞給著色器。如果從影像中采樣的顏色在其所有顏色分量中恰好為 0(忽略 alpha),則意味著您需要將輸入像素原封不動地復制到輸出。否則將其設定為您需要設定的任何內容(黑色或白色或其他)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/405055.html
標籤:
