1

I'm trying to average every 30 frames of a video to create a blurred timelapse. I got the video reading and video writing working, but something is wrong, because I'm only seeing the blue channel! (or one channel that is being written to blue).

Any ideas? Or better ways to do this? I'm new to OpenCV. The code is in Kotlin, but I think it should be the same issue if this was Java or python or whatever.

val videoCapture = VideoCapture(parsedArgs.inputFile)
val frameSize = Size(
        videoCapture.get(Videoio.CV_CAP_PROP_FRAME_WIDTH),
        videoCapture.get(Videoio.CV_CAP_PROP_FRAME_HEIGHT))
val fps = videoCapture.get(Videoio.CAP_PROP_FPS)
val videoWriter = VideoWriter( parsedArgs.outputFile,  VideoWriter.fourcc('M', 'J', 'P', 'G'), fps, frameSize)
val image = Mat(frameSize,CV_8UC3)
val blended = Mat(frameSize,CV_64FC3)
println("Size: $frameSize fps:$fps over $frameCount frames")

try {
    while (videoCapture.read(image)) {
        val frameNumber = videoCapture.get(Videoio.CAP_PROP_POS_FRAMES).toInt()
        Core.flip(image, image, -1) // I shot the video upside down
        Imgproc.accumulate(image,blended)
        if(frameNumber>0 && frameNumber%parsedArgs.windowSize==0) {
            Core.multiply(blended, Scalar(1.0/parsedArgs.windowSize), blended)
            blended.convertTo(image, CV_8UC3);
            videoWriter.write(image)
            blended.setTo(Scalar(0.0,0.0,0.0))
            println(frameNumber.toDouble()/frameCount)
        }
    }
} finally {
    videoCapture.release()
    videoWriter.release()
}
Benjamin H
  • 5,164
  • 6
  • 34
  • 42

2 Answers2

2

Martin Beckett led me to the right answer (thank you!). I was multiplying by a Scalar(double), which should have been my hint because I wasn't multiplying by plain-double.

It expected a Scalar, with a value for each channel so it was happily multiplying my first channel by double, and the rest by 0.

Imgproc.accumulate(image, blended64)
    if (frameNumber > 0 && frameNumber % parsedArgs.windowSize == 0) {
    val blendDivisor = 1.0 / parsedArgs.windowSize
    Core.multiply(blended64, Scalar(blendDivisor, blendDivisor, blendDivisor), blended64)
Benjamin H
  • 5,164
  • 6
  • 34
  • 42
1

My guess would be using different types in Imgproc.accumulate(image,blended) try converting image to match blended before combining them.

If it was writing the entire 8bit*3 pixel data into one float the first field in an openCV image is blue (it uses BGR order)

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • That makes so much sense that I'm accepting the answer right now, and I'll only return if it wasn't it. :) Thank you! – Benjamin H Oct 13 '17 at 16:44