在Java中同步线程的问题

时间:2016-02-11 15:15:17

标签: java multithreading opencv

好的,所以我做了我的研究,这里有很多关于线程同步的问题,但是没有它们真的很重要。我目前正在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将意味着线程在等待线程使用锁来完成它使用对象这将意味着一个缓慢的系统,所以我的问题是如何同时运行这些线程而不必等待其他人?

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

 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();

}

1 个答案:

答案 0 :(得分:1)

由于没有其他人回复,我将会去。

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

要做的第一件事就是做一些性能分析,因为没有必要让它们并行运行,如果它们不会减慢速度的话。

那就是说,我认为你可以采取三种方法。

  1. 每个帧都有一个线程处理,但是有一个并行处理帧的线程池。如果需要一秒钟来处理帧并且你有25fps,则需要至少25个线程才能跟上帧速率。你总是比实时时间落后一秒,但你应该能够跟上帧速率。
  2. 实现此目的的典型方法是将传入帧放入队列中。然后,您有一个线程池从队列中读取最新帧并进行处理。这种设计的缺点是,您无法保证以何种顺序获得处理结果,因此您可能需要在排序结果时添加更多逻辑。

    优点是:

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

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

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

    我个人首先尝试选项1,因为它快速而简单。