0

I have a 2D array as shown below:

[[118 127 133 ..., 213 211 211]
 [125 128 130 ..., 213 213 213]
 [119 124 130 ..., 214 213 213]
 ...,
 [ 36  54  44 ..., 109 101 101]
 [ 37  52  47 ..., 112 101 101]
 [ 39  50  51 ..., 104  99  99]]

I need to apply a threshold on this matrix locally with and without overlapping them. I need to break this 2D matrix into smaller 2D matrix. And then compute a new threshold for the smaller 2D matrix and apply the threshold to smaller 2D matrix and do the same for all the smaller matrices. I have to combine them all in the end. Is there any python function that do this easily? Thank you.

EDIT

import sys
from numpy import *

import scipy.misc
from matplotlib import pyplot

def otsu1( hist, total ):

    no_of_bins = len( hist ) # should be 256

    intra_class_variances = []

    for threshold in range( 0, no_of_bins ):
        # first we try to find the weight and variance on the background
        sum_background      = float(sum( hist[0:threshold] ))
        weight_background   = sum_background / total
        mean_background     = 0.0
        variance_background = 0.0

        # print weight_background

        if sum_background > 0.0: # avoid division by zero
            for x in range( 0, threshold ):
                mean_background += x * hist[x]
            mean_background /= sum_background

            for x in range( 0, threshold ):
                variance_background += (x - mean_background) ** 2 * hist[x]
            variance_background /= sum_background   


        # then we do it for the foreground
        sum_foreground      = float(sum( hist[threshold:no_of_bins] ))
        weight_foreground   = sum_foreground / total
        mean_foreground     = 0.0
        variance_foreground = 0.0

        if sum_foreground > 0.0:
            for x in range( threshold, no_of_bins ):
                mean_foreground += x * hist[x]
            mean_foreground /= sum_foreground

            for x in range( threshold, no_of_bins ):
                variance_foreground += (x - mean_foreground) ** 2 * hist[x]
            variance_foreground /= sum_foreground   

        # print variance_foreground, mean_foreground

        # find the variances within these two classes
        intra_class_variances.append( weight_background * variance_background + weight_foreground * variance_foreground )

    print argmin( intra_class_variances ) - 1

    # use the threshold that has the minimum intra class variance
    return argmin( intra_class_variances ) - 1


def main():
    img = scipy.misc.imread( 'Otsu_test_1.jpg' )
    # print img
    # resize to a more managable size
    # img = scipy.misc.imresize( img, (1944 / 4, 2592 / 4) ) 

    # convert to grayscale
    # grayscale = img.dot( [0.299, 0.587, 0.144] ) 
    rows, cols = shape( img )

    # create 256 bins histogram
    hist = histogram( img, 256 )[0]
    # print len(hist)
    # print hist

    # apply the otsu thresholding
    thresh = otsu1( hist, rows * cols )
    # print thresh

    figure  = pyplot.figure( figsize=(14, 6) )
    figure.canvas.set_window_title( 'Otsu thresholding' )

    axes    = figure.add_subplot(121)
    axes.set_title('Original')
    axes.get_xaxis().set_visible( False )
    axes.get_yaxis().set_visible( False )
    axes.imshow( img, cmap='Greys_r' )

    axes    = figure.add_subplot(122)
    axes.set_title('Otsu thresholding')
    axes.get_xaxis().set_visible( False )
    axes.get_yaxis().set_visible( False )
    axes.imshow( img >= thresh, cmap='Greys_r' )

    pyplot.show()

if __name__ == '__main__':
    main()

Otsu's Threshold

x = blockshaped(img, 4, 10)

for i, j in enumerate(x):
    hist = np.histogram(j, bins=256)[0]
    otsu_thres = otsu_threshold(hist, size)
    print otsu_thres
    x[i] = j >= otsu_thres

p = unblockshaped(x, 188, 250)
Pete
  • 754
  • 2
  • 13
  • 27
  • Are you allowed to use `numpy`? How do you compute the threshold for each submatrix? – rayryeng Mar 20 '15 at 19:49
  • I'm wrote an algorithm for Otsu's method to compute the threshold. Well, currently I apply it globally, I don't know how I can apply it locally. – Pete Mar 20 '15 at 19:59
  • Are you applying Otsu's algorithm on each sub-block, or did you compute it globally? If you computed it globally, there isn't a need to threshold each subblock. You can do it threshold individually per pixel. – rayryeng Mar 20 '15 at 20:01
  • It would be extremely helpful if you showed us any code you wrote. I can't really suggest anything until I know what libraries you're using for image I/O. – rayryeng Mar 20 '15 at 20:02
  • I will compute a new threshold for every subblock and then it the subblock. – Pete Mar 20 '15 at 20:03
  • Then what you could do is do an Otsu on each subblock, then threshold each subblock – rayryeng Mar 20 '15 at 20:03
  • I just added some code... you can test this img – Pete Mar 20 '15 at 20:04
  • Thanks. Glad you're using `numpy` lol. What you can do is separate out each block, compute Otsu on that subblock, then threshold each subblock. You'd just piece all of these subblocks together for the final result. – rayryeng Mar 20 '15 at 20:05
  • I am testing that now and I takes too long because the size of my matrix is huge. – Pete Mar 20 '15 at 20:06
  • I just an image and It took about 3-4 minutes to get the computation done. I have the titles mixed up in the picture. The (2,2) image title should be (2, 1) title. – Pete Mar 20 '15 at 20:09
  • In your Otsu implementation, you can speed that up. Don't use a `for` loop when summing over a `numpy` array. Use `sum` combined with products. For example, you can calculate `mean_background` by: `mean_background = numpy.sum(numpy.arange(threshold) * hist[:threshold]) / sum_background`. Try vectorizing all of the summation operations on your `numpy` arrays first, then see if that speeds up things. One rule is to never use loops when going through `numpy` arrays for computations. `numpy` is designed to do things vectorized. – rayryeng Mar 20 '15 at 20:14
  • I did look at that example and they actually have an adaptive one as well where you can specify the subblock size and then you will compute the Otsu's thres and then apply to each subblock. But I need to do that manually. – Pete Mar 20 '15 at 20:16
  • OK. If that's the case, the only way is to loop through each subblock and apply Otsu. There's no way around it, which means that you need to speed up the way Otsu is being calculated. – rayryeng Mar 20 '15 at 20:19
  • @rayryeng Thank you for your replies. I am using on one for loop and then I found an example which gets me each subblock using reshape and It's very slow. Here is the link to that. http://stackoverflow.com/questions/16873441/form-a-big-2d-array-from-multiple-smaller-2d-arrays/16873755#16873755 – Pete Mar 20 '15 at 20:19
  • I just posted my for loop. – Pete Mar 20 '15 at 20:19
  • I know there is a way to optimize the otsu's method. I will try this and see if I get speed up. – Pete Mar 20 '15 at 20:21
  • If your image is large, then getting subblocks will be very slow as you will have hundreds, or thousands of subblocks being generated and being reshaped so that it gets assigned a variable. It comes down to optimizing Otsu. Try implementing vectorized approaches for computing the sums and see if that speeds things up. – rayryeng Mar 20 '15 at 20:21
  • Another comment is that to calculate the `sum_foreground`, it's simply `1 - sum_background`. Remember, the histogram can be represented as a PDF. You are summing up from 0 up to bin `x`, then from bin `x+1` to the end. Summing up from bin `x+1` to the end is the same as taking 1 and subtracting it from the sum of bin 0 up to `x`. It's a small efficiency thing, but this may help speed things up more. – rayryeng Mar 20 '15 at 20:24

0 Answers0