Show a video with transparent background on ARKit

883 Views Asked by At

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?

1

There are 1 best solutions below

0
On

Hi dear friend as you seen in this link .You must be use no between 330 to 360 degree for remove red color.

effectNode.filter = colorCubeFilterForChromaKey(hueAngle: 330)