1''
1''

Reputation: 27095

Multithreading in Android

I'm trying to multithread some OpenCV4Android code. I divide a 432x432 image into 9 144x144 segments and pass each to a different thread:

Thread[] threads = new Thread[9];
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        threads[3*i+j] = new Thread(new MyThread(image.rowRange(144*i, 144*(i+1)).colRange(144*j, 144*(j+1))));
        threads[3*i+j].start();
    }
}

for (Thread thread : threads) try {thread.join();} catch (InterruptedException e) {};

Here is the thread class:

public class MyThread implements Runnable {
    final Mat block;

    public MyThread(Mat block) {
        this.block = block;
    }

    public void run() {
        /* do image processing on block */
        Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(19,19));
        Mat closed = new Mat();
        Imgproc.morphologyEx(block, closed, Imgproc.MORPH_CLOSE, kernel);
        Core.divide(block, closed, block, 1, CvType.CV_32F);
        Core.normalize(block, block, 0, 255, Core.NORM_MINMAX);
        block.convertTo(block, CvType.CV_8UC1);     
        Imgproc.threshold(block, block, -1, 255, Imgproc.THRESH_BINARY_INV+Imgproc.THRESH_OTSU);
    }
}

I have two issues:

  1. Although the threads are modifying the individual blocks correctly, the modifications are not showing up in the final image. This would make sense if Mat block were passed by value to the thread, but Java should be passing its reference to the thread instead.

  2. The runtime is longer than the unthreaded code - in my emulator, it goes up from ~1200 to ~1500 ms. Is this a problem with the emulator, or is multithreading a really bad idea here for some reason?

Upvotes: 4

Views: 941

Answers (3)

1&#39;&#39;
1&#39;&#39;

Reputation: 27095

The first problem was being caused by the conversion of the block Mat to a different type in this section:

Core.divide(block, closed, block, 1, CvType.CV_32F);
Core.normalize(block, block, 0, 255, Core.NORM_MINMAX);
block.convertTo(block, CvType.CV_8UC1);     

I'm not sure why this should be a problem, but I fixed it by storing the intermediate floating-point matrix in closed and only putting the final answer back into block:

Core.divide(block, closed, closed, 1, CvType.CV_32F);
Core.normalize(closed, block, 0, 255, Core.NORM_MINMAX, CvType.CV_8U);

Upvotes: 1

faylon
faylon

Reputation: 7450

Luis has addressed the second problem. And i think the first issue is because that you process a new Mat to the thread, the modification on the new Mat will not effect the old one.

I find the source code of rowRange, there is some native code but clearly it creates a new object.

 public Mat rowRange(int startrow, int endrow)
 {

     Mat retVal = new Mat(n_rowRange(nativeObj, startrow, endrow));

     return retVal;
 }

Upvotes: 0

Luis
Luis

Reputation: 12048

I've no experience with OpenCV, so I'll address only the second issue.

A thread needs a CPU to run (or a core which acts as a virtual CPU). So, you will never have more threads running in silmultaneous then the real number of cores available in the device.

Let's assume you have a device with 2 cores and you split the work in 9 threads. The final result is that only 2 out of 9 threads will run in silmultaneous, while the remaining 7 will be in the queue waiting for their turn to have CPU.

As there is a cost in Thread creation and switching, the overall performance result would be worse then having only 2 threads.

If you are spliting the work between threads for performance reasons, don't make more threads then the number of cores in the device.

I believe that most devices on market are limited to 1 or 2 cores ...

Regards

Upvotes: 3

Related Questions