【问题标题】:How to display OpenCV webcam capture frame in JavaFX app如何在 JavaFX 应用程序中显示 OpenCV 网络摄像头捕获帧
【发布时间】:2020-07-20 10:29:12
【问题描述】:

我正在使用 JavaFX 创建桌面应用程序,它允许您从网络摄像头扫描二维码。

我决定选择 JavaCV 来处理网络摄像头捕获。然而,问题在于CanvasFrame 类创建了一个Swing JFrame。我的主要目标是找到将它与 JavaFX 组件集成的最佳方式。

我的问题是是否可以在 JPanel(或其他 Swing/JavaFx 组件)中创建 CanvasFrame,而不是在 JFrame 中。在这个选项中,我会将JPanel 包装成SwingNode - 它解决了我的集成问题。

在我的情况下,我还要求其他解决 JavaFX 与 JavaCV 集成问题的建议。 也许有一种直接的方法可以将相机屏幕嵌入到 JavaFx 组件中。

我在下面粘贴测试代码。我的代码是用kotlin写的,但是不影响问题:

import com.google.zxing.*
import com.google.zxing.client.j2se.BufferedImageLuminanceSource
import com.google.zxing.common.HybridBinarizer
import org.bytedeco.javacv.*
import java.awt.image.BufferedImage
import java.util.*
import java.util.concurrent.Executors

class Test {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            Executors.newSingleThreadExecutor().execute { testWebcam() }
        }

        private fun testWebcam() {
            val grabber: OpenCVFrameGrabber = OpenCVFrameGrabber(0);
            val canvasFrame: CanvasFrame = CanvasFrame("Cam")
            grabber.start()

            while (canvasFrame.isVisible) {
                val frame: Frame = grabber.grabFrame() ?: break
                canvasFrame.showImage(frame)
                decodeQrCode(grabber)
            }
        }

        private fun decodeQrCode(grabber: OpenCVFrameGrabber) {
            val java2DFrameConverter: Java2DFrameConverter = Java2DFrameConverter()

            val frame: Frame = grabber.grabFrame()
            val image = java2DFrameConverter.getBufferedImage(frame)

            val decodedQr = parseQr(image)
            println(decodedQr)
        }

        private fun parseQr(image: BufferedImage): String? {

            val reader: MultiFormatReader = MultiFormatReader()
            val binaryBitmap: BinaryBitmap =
                BinaryBitmap(HybridBinarizer(BufferedImageLuminanceSource(image)))

            val hints: Hashtable<DecodeHintType, Any> = Hashtable()
            hints[DecodeHintType.CHARACTER_SET] = "UTF-8"
            hints[DecodeHintType.POSSIBLE_FORMATS] = listOf(BarcodeFormat.QR_CODE)

            return try {
                reader.decode(binaryBitmap, hints).text
            } catch (e: NotFoundException) {
                null;
            }

        }
    }
}

【问题讨论】:

    标签: swing kotlin javafx qr-code javacv


    【解决方案1】:

    https://github.com/rladstaetter/javacv-webcam 有一个项目,其中包含将 javacv 与 Swing、JavaFX 一起使用的示例,以及在 OpenCV 和 JavaFX 的 PixelBuffer 之间使用共享内存缓冲区的新方法。

    您可以使用由共享 ByteBuffer 支持的 JavaFX 的 ImageView,而不是使用 CanvasFrame。伪代码为:

    import java.nio.ByteBuffer
    
    import javafx.scene.image._
    import org.bytedeco.javacv.Frame
    import org.bytedeco.opencv.global.opencv_imgproc._
    import org.bytedeco.opencv.opencv_core.Mat
    
    val videoView: ImageView = ImageView()
    val grabber: OpenCVFrameGrabber = OpenCVFrameGrabber(0)
    grabber.start()
    
    // Fire off a thread to grab frames while the camera is active
    // Each frame will ber passed to the updateView method below
    // ... timer/thread omitted for brevity
    
    val javaCVMat = Mat()
    
    /** create buffer only once saves much time! */
    val buffer: ByteBuffer = javaCVMat.createBuffer()
    
    val formatByte: WritablePixelFormat<ByteBuffer> = PixelFormat.getByteBgraPreInstance()
    
    fun updateView(frame: Frame): Unit = {
      val w = frame.imageWidth()
      val h = frame.imageHeight()
    
      val mat = javaCVConv.convert(frame)
      cvtColor(mat, javaCVMat, COLOR_BGR2BGRA)
    
      val pb = PixelBuffer(w, h, buffer, formatByte)
      val wi = WritableImage(pb)
      videoView.setImage(wi)
    }
    
    

    【讨论】:

      【解决方案2】:

      我解决了我的问题。就我而言,最好的解决方案是使用Java2DFrameConverter:

      import javafx.application.Application
      import javafx.embed.swing.SwingFXUtils
      import javafx.scene.Scene
      import javafx.scene.image.ImageView
      import javafx.scene.image.WritableImage
      import javafx.scene.layout.VBox
      import javafx.stage.Stage
      import org.bytedeco.javacv.Frame
      import org.bytedeco.javacv.Java2DFrameConverter
      import org.bytedeco.javacv.OpenCVFrameGrabber
      import java.awt.image.BufferedImage
      import java.util.concurrent.Executors
      
      class StackOverflow : Application() {
          private val java2DFrameConverter: Java2DFrameConverter = Java2DFrameConverter()
      
          companion object {
              @JvmStatic
              fun main(args: Array<String>) {
                  launch(StackOverflow::class.java)
              }
          }
      
          override fun start(primaryStage: Stage) {
              val grabber: OpenCVFrameGrabber = OpenCVFrameGrabber(0)
              grabber.start()
      
              val imageView: ImageView = ImageView()
      
              Executors.newSingleThreadExecutor().execute {
                  while (true) {
                      val frame = grabber.grabFrame()
                      imageView.image = frameToImage(frame)
                  }
              }
      
              val scene: Scene = Scene(VBox(imageView), 800.0, 800.0)
              primaryStage.scene = scene
              primaryStage.show()
          }
      
          private fun frameToImage(frame: Frame): WritableImage {
              val bufferedImage: BufferedImage = java2DFrameConverter.getBufferedImage(frame)
              return SwingFXUtils.toFXImage(bufferedImage, null)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-02-21
        • 2012-03-23
        • 1970-01-01
        • 2015-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-12
        • 2020-03-06
        相关资源
        最近更新 更多