【问题标题】:Problems Synchronizing threads in Java在 Java 中同步线程的问题
【发布时间】:2016-02-12 01:47:00
【问题描述】:

好的,所以我做了我的研究,这里有很多关于线程同步的问题,但没有一个真正切中要害。我目前在 Opencv 中工作,我从包含车辆的摄像头中获取一个帧,移除背景并跟踪车辆,但在此之前,我会进行一些预处理和后处理,例如通过模糊去除噪声,所有这些都运行一个线程,它工作得很好,但出现了一个问题,我现在想读取车牌,为此我需要一个更高分辨率的帧,否则对于每一帧我都不会检测到单个车牌,但是一旦我增加我的帧大小我的性能受到影响,我的线程速度变慢,以至于我的程序不再符合实时系统的条件。

所以我想在我的场景中添加更多线程,每个线程都专注于一项任务 这是我的任务列表

 //recieves fame from Camera
 1. preprocess
 //recieves a Frame from preprocess and removes the background
 2. remove background
//recieves a Frame from backgroundremover and tracks the vehicles
 3. postprocess

如果我一个接一个地运行线程,我认为它仍然会很慢,而不是我认为或同时运行线程,但是它们使用相同对象的问题,声明它们volatile 将意味着线程等待带锁的线程完成它以使用该对象,这将再次意味着系统缓慢,所以我的问题是如何同时运行这些线程而不必等待其他线程?

我在Java 中查看了十几个multithreading 技术,但发现很难想出一种方法来实现这项工作。 到目前为止,我已经看过了

 1. Thread synchronization using the keyword volatile
 2. Thread synchronization using the keyword synchronized
 3. Multiple thread locks using a lock object
 4. Using threadpools
 5. Using the Countdown Latch
 6. Wait and motify
 7. Using Semaphores(which seemed like a good idea).

这是我想分解成这些线程的代码

public void VideoProcessor()
{


    videProcessorThread = new Thread(new Runnable()
            {

        @Override
        public void run()
        {

            try{

                int i = 0;
                while (isPlaying() && isMainScreenONOFF()) {

                    camera.read(frame);
                    //set default and max frame speed
                    camera.set(Videoio.CAP_PROP_FPS, 25);
                    //get frame speed just incase it did not set
                    fps = camera.get(Videoio.CAP_PROP_FPS);
                    //if(frame.height() > imgHeight || frame.width() > imgWidth)
                    Imgproc.resize(frame, frame, frameSize);
                    //check if to convert or not
                    if(getblackAndWhite())
                    Imgproc.cvtColor(frame, frame, Imgproc.COLOR_RGB2GRAY);

                    imag = frame.clone();
                    if(rOI){

                    //incase user adjusted the lines we try calculate there new sizes
                    adjustLinesPositionAndSize(xAxisSlider.getValue(), yAxisSlider.getValue());
                    //then we continue and draw the lines

                    if(!roadIdentified)
                    roadTypeIdentifier(getPointA1(), getPointA2());
                    }

                    viewClass.updateCarCounter(tracker.getCountAB(), tracker.getCountBA());


                    if (i == 0) {
                        // jFrame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
                        diffFrame = new Mat(outbox.size(), CvType.CV_8UC1);
                        diffFrame = outbox.clone();
                    }

                    if (i == 1) {
                        diffFrame = new Mat(frame.size(), CvType.CV_8UC1);

                        removeBackground(frame, diffFrame, mBGSub, thresHold.getValue(), learningRate.getValue());

                        frame = diffFrame.clone();
                        array = detectionContours(diffFrame, maximumBlob.getValue(), minimumBlob.getValue());
                        Vector<VehicleTrack> detections = new Vector<>();
                        Iterator<Rect> it = array.iterator();
                        while (it.hasNext()) {
                            Rect obj = it.next();           
                            int ObjectCenterX = (int) ((obj.tl().x + obj.br().x) / 2);
                            int ObjectCenterY = (int) ((obj.tl().y + obj.br().y) / 2);
                            //try counter

                            //add centroid and bounding rectangle
                            Point pt = new Point(ObjectCenterX, ObjectCenterY);
                            VehicleTrack track = new VehicleTrack(frame, pt, obj);

                            detections.add(track);
                        }
                        if (array.size() > 0) {
                            tracker.update(array, detections, imag);
                            Iterator<Rect> it3 = array.iterator();
                            while (it3.hasNext()) {
                                Rect obj = it3.next();

                                int ObjectCenterX = (int) ((obj.tl().x + obj.br().x) / 2);
                                int ObjectCenterY = (int) ((obj.tl().y + obj.br().y) / 2);
                                Point pt = null;
                                pt = new Point(ObjectCenterX, ObjectCenterY);                                   
                                Imgproc.rectangle(imag, obj.br(), obj.tl(), new Scalar(0, 255, 0), 2);
                                Imgproc.circle(imag, pt, 1, new Scalar(0, 0, 255), 2);
                                //count and eleminate counted
                                tracker.removeCounted(tracker.tracks);
                            }
                        } else if (array.size() == 0) {
                            tracker.updateKalman(imag, detections);
                        }
                    }

                    i = 1;  
                    //Convert Image and display to View
                   displayVideo();
                }
                //if error occur or video finishes
                Image image = new Image("/assets/eyeMain.png");  
                viewClass.updateMainImageView(image);

                }catch(Exception e)
                {
                    e.printStackTrace();
                    System.out.println("Video Stopped Unexpectedly");
                }
            //thread is done    

          }
        });videProcessorThread.start();

}

【问题讨论】:

    标签: java multithreading opencv


    【解决方案1】:

    由于没有其他人回复,我会试一试。

    您已经涵盖了问题中的主要技术方面(锁定、同步等)。无论您如何看待它,都没有设计多线程系统的通用解决方案。如果你有线程访问相同的对象,你需要设计你的同步,你可以让线程互相阻塞,减慢一切。

    首先要做的是进行一些性能分析,因为如果它们不减慢速度,那么让它们并行运行是没有意义的。

    也就是说,我认为您可以采用三种方法。

    1. 有一个线程处理每个帧,但有一个线程池并行处理帧。如果处理一帧需要一秒钟并且您有 25fps,那么您至少需要 25 个线程才能跟上帧速率。你总是比实时慢一秒,但你应该能够跟上帧速率。

    实现这一点的典型方法是将传入的帧放入队列中。然后你有一个线程池从队列中读取最新的帧并处理它。这种设计的缺点是您无法保证以何种顺序获得处理结果,因此您可能需要添加更多关于对结果进行排序的逻辑。

    优点是:

    • 几乎没有争用,只是将帧从队列中取出,这应该是最小的
    • 通过调整线程数很容易调整和扩展。它甚至可以在多台机器上运行,具体取决于在机器之间移动帧的难易程度
    • 您可以避免每次创建新线程的开销,因为每个线程都在逐帧处理
    • 很容易监控,因为您只需查看队列的大小即可
    • 可以轻松实现错误处理,例如,如果线程崩溃,则使用 ActiveMQ 重新排队帧。

      1. 并行运行部分算法。您编写它的方式(预处理,处理,后处理),我认为这不合适,因为您不能在预处理的同时进行后处理。但是,如果您可以在可以并行运行的步骤中表达您的算法,那么它可能会起作用。

      2. 尝试并行运行代码的特定部分。查看您发布的代码,迭代器是显而易见的选择。有什么理由不并行运行迭代器循环吗?如果可以,请尝试使用 Java 并行流,看看是否能带来任何性能提升。

    我个人会先尝试选项 1,因为它既快速又简单。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      • 2020-02-01
      • 1970-01-01
      相关资源
      最近更新 更多