I am trying to simply show a video removing part of its background which is meant to be transparent. I've tried several approaches courtesy of Stack Overflow, and so far they are all sub-par. The one that came closest to the results I'm seeking is the one in this link: ARKit / SpriteKit - set pixelBufferAttributes to SKVideoNode or make transparent pixels in video (chroma-key effect) another way
However, as sensible as the approach is, and as much as it seems to be working for the person who asked the question, in my case it only turns the whole video white.
My strategy is to show the video and add the effect as follows:
func setVideoNode(named name: String, in node: SCNNode, with imageReference: ARReferenceImage?, size: CGSize = CGSize(width: 500, height: 320), extension ext: String = "mp4") {
let nodeWidth = imageReference!.physicalSize.width
let nodeHeigth = imageReference!.physicalSize.height
guard let videoUrl = Bundle.main.url(forResource: name, withExtension: ext) else {
print("Guard Fail")
return
}
self.currentPlayer = AVPlayer(url: videoUrl)
let videoNode = SKVideoNode(avPlayer: self.currentPlayer)
videoNode.size = size
videoNode.name = name
videoNode.yScale = -1.0
videoNode.play()
let effectNode = SKEffectNode()
effectNode.addChild(videoNode)
effectNode.filter = colorCubeFilterForChromaKey(hueAngle: 0)
let planeGeometry = SCNPlane(width: nodeWidth, height: nodeHeigth)
planeGeometry.firstMaterial?.diffuse.contents = effectNode
planeGeometry.firstMaterial?.isDoubleSided = true
let planeNode = SCNNode()
planeNode.geometry = planeGeometry
planeNode.position = SCNVector3(planeNode.position.x + 1, 0.5, 0)
planeNode.eulerAngles.x = -.pi / 2
node.addChildNode(planeNode)
self.currentPlayer.play()
}
func RGBtoHSV(r : Float, g : Float, b : Float) -> (h : Float, s : Float, v : Float) {
var h : CGFloat = 0
var s : CGFloat = 0
var v : CGFloat = 0
let col = UIColor(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: 1.0)
col.getHue(&h, saturation: &s, brightness: &v, alpha: nil)
return (Float(h), Float(s), Float(v))
}
func colorCubeFilterForChromaKey(hueAngle: Float) -> CIFilter {
let hueRange: Float = 20 // degrees size pie shape that we want to replace
let minHueAngle: Float = (hueAngle - hueRange/2.0) / 360
let maxHueAngle: Float = (hueAngle + hueRange/2.0) / 360
let size = 64
var cubeData = [Float](repeating: 0, count: size * size * size * 4)
var rgb: [Float] = [0, 0, 0]
var hsv: (h : Float, s : Float, v : Float)
var offset = 0
for z in 0 ..< size {
rgb[2] = Float(z) / Float(size) // blue value
for y in 0 ..< size {
rgb[1] = Float(y) / Float(size) // green value
for x in 0 ..< size {
rgb[0] = Float(x) / Float(size) // red value
hsv = RGBtoHSV(r: rgb[0], g: rgb[1], b: rgb[2])
// TODO: Check if hsv.s > 0.5 is really nesseccary
let alpha: Float = (hsv.h > minHueAngle && hsv.h < maxHueAngle && hsv.s > 0.5) ? 0 : 1.0
cubeData[offset] = rgb[0] * alpha
cubeData[offset + 1] = rgb[1] * alpha
cubeData[offset + 2] = rgb[2] * alpha
cubeData[offset + 3] = alpha
offset += 4
}
}
}
let b = cubeData.withUnsafeBufferPointer { Data(buffer: $0) }
let data = b as NSData
let colorCube = CIFilter(name: "CIColorCube", parameters: [
"inputCubeDimension": size,
"inputCubeData": data
])
return colorCube!
}
In my case, I'm trying to remove reds. Is there any other way to achieve this?
Hi dear friend as you seen in this link .You must be use no between
330 to 360 degree
for remove red color.