0

Finally, I succeeded in changing the MATLAB code to Python code.

However, contrary to what i have heard, Python's execution speed was remarkably slow.

Is MATLAB better on the image processing side these days?

Of course, I have no choice but to use Python because the company doesn't buy MATLAB...

ps. run Python in visual studio environment and IDLE.

If there's a way to speed Python up, please help me.

## Exercise Python image processing ##

import numpy as np
import cv2
import matplotlib.pyplot as plt

B = cv2.imread(r'D:\remedi\Exercise\Xray\Offset.png', -1) # offset image

for i in range(2,3):

    org_I = cv2.imread(r'D:\remedi\Exercise\Xray\objects\object (' + str(i) + ').png', -1) # original image

    w = cv2.imread(r'D:\remedi\Exercise\Xray\white\white (' + str(i) + ').png', -1) # white image

    # dead & bad pixel correction
    corrected_w = w.copy()
    corrected_org_I = org_I.copy()

    c = np.mean(corrected_w)
    p = np.abs(corrected_w - c)

    sens = 0.7
    [num_y, num_x] = np.where((p < c*sens) | (p > c*sens))

    ar = np.zeros((3,3))
    ar2 = np.zeros((3,3))
    for n in range(0, num_y.shape[0]):
        for j in range(-1,2):
            for k in range(-1,2):
                if num_y[n]+j+1 == 0 or num_x[n]+k+1 == 0 or num_y[n]+j+1 == 577 or num_x[n]+k+1 == 577:
                    ar[j+1][k+1] = 0
                    ar2[j+1][k+1] = 0
                else:
                    ar[j+1][k+1] = corrected_w[num_y[n]+j-1][num_x[n]+k-1]
                    ar2[j+1][k+1] = corrected_org_I[num_y[n]+j-1][num_x[n]+k-1]
        ar[1][1] = 0
        ar2[1][1] = 0
        corrected_w[num_y[n]][num_x[n]] = np.sum(ar)/np.count_nonzero(ar)
        corrected_org_I[num_y[n]][num_x[n]] = np.sum(ar2)/np.count_nonzero(ar2)

c = np.mean(corrected_w) # constant

FFC = np.uint16(np.divide(c*(corrected_org_I-B), (corrected_w-B))) # flat field correction

plt.subplot(2,3,1), plt.imshow(org_I, cmap='gray'), plt.title('Original Image')
plt.subplot(2,3,2), plt.imshow(corrected_org_I, cmap='gray'), plt.title('corrected original Image')
plt.subplot(2,3,3), plt.imshow(FFC, cmap='gray'), plt.title('FFC')
plt.subplot(2,3,4), plt.imshow(w, cmap='gray'), plt.title('w')
plt.subplot(2,3,5), plt.imshow(corrected_w, cmap='gray'), plt.title('corrected w')
plt.subplot(2,3,6), plt.imshow(B, cmap='gray'), plt.title('B')
plt.show()

Miki
  • 40,887
  • 13
  • 123
  • 202
  • 2
    Sorry, where did you hear that Python is fast? – iz_ Jan 14 '20 at 02:39
  • 2
    There are a lot of ways to speed up Python, but it won't be as fast as a compiled language. That said, you can use the C API and some third-party libraries to speed up specific tasks. Also, good code structure (generators, classes, etc.) will help. – Mark Moretto Jan 14 '20 at 02:42
  • @iz_ remember what the professor doing the image processing said. MATLAB is heavy and slow. –  Jan 14 '20 at 02:45
  • @MarkMoretto So how difficult is it to convert Python to C++? I haven't done C++ before. Can I try it quickly after studying? –  Jan 14 '20 at 02:47
  • 2
    I have little experience with MATLAB, but Python is by no means fast! Have you tried profiling your code? I feel like the Python for loops are going to be very slow. – iz_ Jan 14 '20 at 02:49
  • @iz_ In MATLAB, i used a lot of abbreviation for loops, but Python was not used yet, so i used a lot of loops for loops. Of course, the above code execution was the same algorithm, so i used the same for loop. I'll try to reduce the number for loop. Thank you so much! –  Jan 14 '20 at 03:09
  • 2
    `cv2` is a front end to c++ code so probably isn't the problem. The triple nested loop could be slowing you down. `numpy` is like old MATLAB; it is fast when using whole array operations; slow when iterating in Python code. Newer MATLAB lets you be lazy and iterate, because it does a lot of JIT compiling. You have to add `numba` if you want to go that route. You'll see lots of questions about `vectorizing` or 'eliminating loops'; that's what we used to in MATLAB. – hpaulj Jan 14 '20 at 03:18
  • 1
    `for n in range(0, num_y.shape[0]):` is not the correct way to use `numpy.ndarray` objects, this will be *very slow*, much slower than using even a regular Python list object. To effectively use `numpy.ndarray` objects, you must use vectorized operations. Alternatively, there exists `numba` which is a JIT for `numpy` code, and it will speed up this exact sort of code **very very much** – juanpa.arrivillaga Jan 14 '20 at 04:20
  • How can i use ```numba``` ? just write @jit, it occurs error. –  Jan 14 '20 at 05:34
  • MATLAB used to be slow, 20 years ago. MATLAB is actually quite fast nowadays. Python is as slow as MATLAB used to be back in those days. – Cris Luengo Jan 14 '20 at 05:46
  • A Numba example (also on a Matlab to Python problem): https://stackoverflow.com/a/59740213/4045774 – max9111 Jan 14 '20 at 19:08

2 Answers2

1

cv2 calls into c++ library code, there is some overhead to each of these calls. These can add up depending on what you are doing. Additionally opencv takes advantage of some processor optimizations such as SIMD and NEON.

Here is a concrete example, I have implemented my own threshold function by iterating through the pixels. I then use opencv's built-in threshold function. I print timing for each function and compare the final result to verify they are the same.

img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
thresh = 128
thresh_loops = img.copy()

# implement threshold with loops
t1 = cv2.getTickCount()
for c in range(img.shape[0]):
    for r in range(img.shape[1]):
        if thresh_loops[c,r] > thresh:
            thresh_loops[c,r] = 255
        else:
            thresh_loops[c,r] = 0
t2 = cv2.getTickCount()
print((t2-t1)/cv2.getTickFrequency())

# use the threshold function
t1 = cv2.getTickCount()
thr, thresh_fun = cv2.threshold(img, thresh, 255, cv2.THRESH_BINARY)
t2 = cv2.getTickCount()
print((t2-t1)/cv2.getTickFrequency())

print(np.all(thresh_loops == thresh_fun)) # verify the same result

I ran on a 720p image (720x1280 - or approximately 1 million pixels), on my machine the first function too 2.319724256 seconds the second took 0.013217389 seconds. So the second function is approximately 200x faster! You will run into this problem if you use Java or other languages that call into the OpenCV library (or any other C library).

Use it as good motivation to learn the api.

I'll also add that if you are doing image processing in Python with OpenCV, you should also learn the Numpy api, since the matrix (Mat) class is represented as a numpy array. You can get massive speedups by knowing the numpy api as well.

shortcipher3
  • 1,292
  • 9
  • 22
1

I switched to python a year ago from my beloved Matlab. Yes you are right, Matlab is faster than python, usually at least by 3-time or more.

2 ways I found to save python is here

  1. Try to read Numpy Functional programming Routines and replace some for-loops with methods there. They are much faster than slicing an ndarray in side a for-loop.

  2. Try Multiprocessing. I know that Matlab parfor is also better than any parallel computation package in python. Try 'joblib' or 'multiprocessing'. They might help a little bit.

River
  • 572
  • 1
  • 4
  • 11