1

I have photo of flame - data as asc file that contains matrix of pixels. In each pixel is value of light intensity.

My code of plotting:

import os
import numpy as np
import matplotlib.pyplot as plt
# Open a file
path = "input/"
dirs = os.listdir( path )
number_of_files = 0

# This would print all the files and directories
for file in dirs:
    if file.endswith(".asc"):
        img = np.genfromtxt (path+file)

        file = os.path.splitext(file)[0]
        #pasukamas vaizdas
        img = img.transpose ()
        # Just a figure and one subplot
        fig, ax = plt.subplots(1,figsize=(20,20))

        ax.set_title(file, fontsize=60, y=1.03)
        plt.imshow (img, interpolation='nearest', origin='lower')

        plt.colorbar ()
        plt.savefig ('output/' + file + '.png', bbox_inches = 'tight')

        number_of_files = number_of_files + 1
        plt.close(fig)
print (number_of_files)

Result: plotted image

How I can plot images in 3 ranges:

  1. from max intensity to 36000 (red zone)
  2. from max intensity to 27000 (Yellow zone)
  3. from max intensity to 12000 (Blue zone)

and detect most bottom and top pixels? Also most left and right pixels? Then connect top and bottom pixels with line. Need same thing for left and right pixels. How show pixel distance on a lines?

Result must look like that wanted result

talonmies
  • 70,661
  • 34
  • 192
  • 269
Klasik
  • 872
  • 1
  • 9
  • 29
  • Check out http://stackoverflow.com/questions/27977303/scipy-ndimage-measurement-labeling-is-not-working-properly -- note that the sample code defines a threshold and then identifies areas in the image that meet that threshold. That should get you going. – cphlewis Apr 14 '15 at 22:48
  • I'm re-tagging your question, since it's mostly about image processing rather than plotting. – ali_m Apr 16 '15 at 12:19

1 Answers1

2

You seem to want a thresholded version of your image(s), then area labeling on the thresholded values, and some fancy measures afterwards.


For convenience I would form a 3D ndarray of your image sequences , so that any operation can be done in one go with numpy :

fileList = filter(lambda s: s.endswith(".asc"), os.listdir(path))

# open first image so we have its dimensions to initialize the array
firstImage = np.genfromtxt (path+fileList[0])

imageArray = np.zeros((len(filelist),) + firstImage.shape)

Now we assign the values

imageArray[0,:,:] = firstImage
for i,file in enumerate(filelist[1:]):
    # skip the first item because we already have it
    imageArray[i+1,:,:] = np.genfromtxt (path+file)

Ok, now we have a 3D array of your image, so let's get the range images

boolMaskRedzone = imageArray > 36000 
boolMaskYellowzone = imageArray > 27000 
boolMaskYellowzone = imageArray > 12000 

These are now masks of same size as your images but of booleans. Let's fiddle with it :

redParts = image*boolMaskRedZone # images with 0 for thresholded values
plt.imshow(redParts[0,:,:],cmap="hot")

Notice again that redParts and everything else is still in 3D, so we made a 2D view of the array for plotting purposes.


Now the easy / fun part : labeling ! We can use scipy.ndimage.measurements.label()

from scipy.ndimage import label
labelsRed, nbLabelsRed = label(boolMaskRedzone)

labelsRed is now an array with ints as label indices.

Ideally we would have nbLabelsRed == 1, if not, "islands" can be closed with

from scipy.ndimage import morphology
closedLabels = morphology.binary_closing(labelsRed)
# fiddle with the optional iterations parameter if needed

We can compute the area of your labels = thresholded areas by using np.where to give us the positions of pixels, then counting the number of items :

x,y,z = np.where(labelsRed == 1) # x, y ,z are arrays
area = len(x) # the number of pixels that are brighter than red

As for computing the top/bottommost pixels , it can become tricky if you want the line to be a diagonal one, but if you just want top / bottom (aligned with images axes) you can make numpy check when the masks become True for each axis, which is plainly doing the difference (derivation) between the array and and offset version, then first nonzero element along each axis

differenceArray = boolMaskRedZone - np.roll(boolMaskRedZone,1,axis=1)
# now check along each column when the array first becomes True
uselessImageIndex,xTopMostPixel,yTopMostPixel= numpy.where(differenceArray == True)
# found all the crossings and put them in 2 arrays

For exact diagonal measurement, you might want to look into specialized image measurement libraries, like scikit-image, they probably have what you want

If you really want to do it yourself, I would recommend some approach based on finding object centre, then computing diagonal lines position, and measuring the max length, but then what happens if you find a 45 degree line ? Does it become "top-bottom" or "left-right" ? Or do you want the longest line close to horizontal ? Or do you want bi-orthogonal measurement ? (Pick biggest line as first measurement, second diameter line is whatever the length of the line 90 degrees from the first one)

Assuming you have your points in image, the plotting is just a line plot with plt.plot =)

I have to admit I didn't think through the derivation part much, but I assumed that once you'd have the label you would be a happy camper =)

EDIT : Of course all those operations can be computed directly by iterating over the array, but I only posted the approach that produces one-liners that use numpy's array manipulation efficiency to do stuff. You could do indeed do each operation by doing

for x in range(image.shape[0]):
    for y in range(image.shape[1]):
        if(image[x,y] > 36000):
            mask[x,y]=True

but this nesting of loops is very slow compared to numpy's compiled and hardware-accelerated functions (see http://www.astro.washington.edu/users/vanderplas/Astr599/notebooks/11_EfficientNumpy for a demo of speed on python/numpy)

EDIT 2: For another project of mine I've been researching some more of scipy's ndimage functions, and there's something for you : ndimage.center_of_mass().

This function finds the center of mass in an (potentially labelled) array. By finding the center of mass of your labelled array, you would have the center of the axis to find diagonals from, and the rest is just piece of cake ^^

Jiby
  • 1,865
  • 1
  • 13
  • 22
  • That's is perfect answer! I will try code by my self. thank you so much! – Klasik Apr 18 '15 at 11:56
  • maybe u can help little bit more. I need rotate image .asc file has numbering of lines so if I rotate it I get error about not fitting in shape... I need remove first bit of each line when shaping array – Klasik Apr 18 '15 at 15:55
  • Sorry about the python 3 thing, do tell me which commands don't like my syntax (so I'll see what I'm missing) Hmm I have no idea about specifically asc files (never heard of the things ^^) but what I get from your problem is that you need to either "translate" your arrays (in which case try `np.roll(array,1,axis=1)`), or create a smaller size array, and you can do that by editing the array shape at creation (in the `np.zeros`). Did I understand you correctly ? – Jiby Apr 18 '15 at 23:50
  • u can look at my new question. http://stackoverflow.com/questions/29720430/skip-a-specified-number-of-columns-with-numpy-genfromtxt-python-3-4-error – Klasik Apr 19 '15 at 08:47