java - Java线程同步问题

标签 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 将意味着线程等待对于带锁的线程完成它使用对象,这将再次意味着一个缓慢的系统所以我的问题是我如何才能同时运行这些线程而不必等待其他线程?

我看过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. 让一个线程处理每一帧,但让一个线程池并行处理帧。如果处理一帧需要一秒钟,而您有 25fps,则您至少需要 25 个线程才能跟上帧速率。您总是会比实时时间慢大约一秒,但您应该能够跟上帧速率。

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

优点是:

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

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

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

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

关于java - Java线程同步问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35343074/

相关文章:

java - 单击按钮时表格未刷新

java - LinkedHashMap 中的 LinkedHashSet

c++ - Opencv 编解码器选择对话框未显示

java - 我应该怎么做才能停止线程执行?

java - 每 x 秒执行一次代码

xml - OpenCv Haar函数创建的XML内部包含什么。

python - 使用Opencv进行透视变换

java - 如何在 Spring-Integration 中将 SOAPAction header 添加到 HTTP 消息中?

java - 如何创建 Android Facebook key 哈希?

java - 同步与读写锁