Beispiel #1
0
def test_empty_selem():
    # check that min, max and mean returns zeros if structuring element is
    # empty

    image = np.zeros((5, 5), dtype=np.uint16)
    out = np.zeros_like(image)
    mask = np.ones_like(image, dtype=np.uint8)
    res = np.zeros_like(image)
    image[2, 2] = 255
    image[2, 3] = 128
    image[1, 2] = 16

    elem = np.array([[0, 0, 0], [0, 0, 0]], dtype=np.uint8)

    rank.mean(image=image,
              selem=elem,
              out=out,
              mask=mask,
              shift_x=0,
              shift_y=0)
    assert_array_equal(res, out)
    rank.minimum(image=image,
                 selem=elem,
                 out=out,
                 mask=mask,
                 shift_x=0,
                 shift_y=0)
    assert_array_equal(res, out)
    rank.maximum(image=image,
                 selem=elem,
                 out=out,
                 mask=mask,
                 shift_x=0,
                 shift_y=0)
    assert_array_equal(res, out)
Beispiel #2
0
def test_smallest_selem16():
    # check that min, max and mean returns identity if structuring element
    # contains only central pixel

    image = np.zeros((5, 5), dtype=np.uint16)
    out = np.zeros_like(image)
    mask = np.ones_like(image, dtype=np.uint8)
    image[2, 2] = 255
    image[2, 3] = 128
    image[1, 2] = 16

    elem = np.array([[1]], dtype=np.uint8)
    rank.mean(image=image,
              selem=elem,
              out=out,
              mask=mask,
              shift_x=0,
              shift_y=0)
    assert_array_equal(image, out)
    rank.minimum(image=image,
                 selem=elem,
                 out=out,
                 mask=mask,
                 shift_x=0,
                 shift_y=0)
    assert_array_equal(image, out)
    rank.maximum(image=image,
                 selem=elem,
                 out=out,
                 mask=mask,
                 shift_x=0,
                 shift_y=0)
    assert_array_equal(image, out)
Beispiel #3
0
def test_compare_with_cmorph_erode():
    # compare the result of maximum filter with erode

    image = (np.random.rand(100, 100) * 256).astype(np.uint8)
    out = np.empty_like(image)
    mask = np.ones(image.shape, dtype=np.uint8)

    for r in range(1, 20, 1):
        elem = np.ones((r, r), dtype=np.uint8)
        rank.minimum(image=image, selem=elem, out=out, mask=mask)
        cm = cmorph._erode(image=image, selem=elem)
        assert_array_equal(out, cm)
def test_compare_with_cmorph_erode():
    # compare the result of maximum filter with erode

    image = (np.random.random((100, 100)) * 256).astype(np.uint8)
    out = np.empty_like(image)
    mask = np.ones(image.shape, dtype=np.uint8)

    for r in range(1, 20, 1):
        elem = np.ones((r, r), dtype=np.uint8)
        rank.minimum(image=image, selem=elem, out=out, mask=mask)
        cm = cmorph.erode(image=image, selem=elem)
        assert_array_equal(out, cm)
Beispiel #5
0
def test_percentile_min():
    # check that percentile p0 = 0 is identical to local min
    img = data.camera()
    img16 = img.astype(np.uint16)
    selem = disk(15)
    # check for 8bit
    img_p0 = rank.percentile(img, selem=selem, p0=0)
    img_min = rank.minimum(img, selem=selem)
    assert_array_equal(img_p0, img_min)
    # check for 16bit
    img_p0 = rank.percentile(img16, selem=selem, p0=0)
    img_min = rank.minimum(img16, selem=selem)
    assert_array_equal(img_p0, img_min)
Beispiel #6
0
def test_percentile_min():
    # check that percentile p0 = 0 is identical to local min
    img = data.camera()
    img16 = img.astype(np.uint16)
    selem = disk(15)
    # check for 8bit
    img_p0 = rank.percentile(img, selem=selem, p0=0)
    img_min = rank.minimum(img, selem=selem)
    assert_array_equal(img_p0, img_min)
    # check for 16bit
    img_p0 = rank.percentile(img16, selem=selem, p0=0)
    img_min = rank.minimum(img16, selem=selem)
    assert_array_equal(img_p0, img_min)
Beispiel #7
0
def substract_background(data, radius, background='mean', show=0):
    dmin, dmax = data.min(), data.max()
    tmp = ((data - dmin) / (dmax - dmin) * 255).astype(np.uint8)
    lforeground = rank.minimum(tmp, disk(radius // 2))

    if background == 'mean':
        lbackground = rank.mean(lforeground, disk(radius * 4)).astype(int)
    elif background == 'median':
        lbackground = rank.median(lforeground, disk(radius * 4)).astype(int)
    elif background == 'maximum':
        lbackground = rank.maximum(lforeground, disk(radius * 4)).astype(int)
    else:
        lbackground = rank.modal(lforeground, disk(radius * 4)).astype(int)

    rdata = (lforeground - lbackground)

    if show > 2:
        fig, axes = plt.subplots(ncols=3, nrows=1, figsize=(30, 10))
        for ax, im, title in zip(axes, [lforeground, lbackground, rdata],
                                 ['Foreground', 'Background', 'Substraction']):
            ax.imshow(im, 'optiona')
            ax.set_xticks([])
            ax.set_yticks([])
            ax.set_title(title)
        plt.show()

    return rdata
Beispiel #8
0
def test_16bit():
    image = np.zeros((21, 21), dtype=np.uint16)
    selem = np.ones((3, 3), dtype=np.uint8)

    for bitdepth in range(17):
        value = 2**bitdepth - 1
        image[10, 10] = value
        assert rank.minimum(image, selem)[10, 10] == 0
        assert rank.maximum(image, selem)[10, 10] == value
        assert rank.mean(image, selem)[10, 10] == int(value / selem.size)
Beispiel #9
0
def test_16bit():
    image = np.zeros((21, 21), dtype=np.uint16)
    selem = np.ones((3, 3), dtype=np.uint8)

    for bitdepth in range(17):
        value = 2 ** bitdepth - 1
        image[10, 10] = value
        assert rank.minimum(image, selem)[10, 10] == 0
        assert rank.maximum(image, selem)[10, 10] == value
        assert rank.mean(image, selem)[10, 10] == int(value / selem.size)
Beispiel #10
0
def test_smallest_selem16():
    # check that min, max and mean returns identity if structuring element
    # contains only central pixel

    image = np.zeros((5, 5), dtype=np.uint16)
    out = np.zeros_like(image)
    mask = np.ones_like(image, dtype=np.uint8)
    image[2, 2] = 255
    image[2, 3] = 128
    image[1, 2] = 16

    elem = np.array([[1]], dtype=np.uint8)
    rank.mean(image=image, selem=elem, out=out, mask=mask,
              shift_x=0, shift_y=0)
    assert_array_equal(image, out)
    rank.minimum(image=image, selem=elem, out=out, mask=mask,
                 shift_x=0, shift_y=0)
    assert_array_equal(image, out)
    rank.maximum(image=image, selem=elem, out=out, mask=mask,
                 shift_x=0, shift_y=0)
    assert_array_equal(image, out)
    def run(self, workspace):
 
        image = workspace.image_set.get_image(self.image_name.value)
        nuclei_image = image.pixel_data[:,:]
        image_collection = []
      
        #
        #Get the global Threshold with Otsu algorithm and smooth nuclei image
        #
#         nuclei_smoothed = self.smooth_image(image_collection[3][0], image.mask, 1)

        global_threshold_nuclei = otsu(nuclei_image, min_threshold=0, max_threshold=1)
        print "the threshold compute by the Otsu algorythm is %f" % global_threshold_nuclei      
        
        
        #
        #Binary thee "DAPI" Image (Nuclei) and labelelize the nuclei
        #

        binary_nuclei = (nuclei_image >= global_threshold_nuclei)
        labeled_nuclei, object_count = scipy.ndimage.label(binary_nuclei, np.ones((3,3), bool))
        print "the image got %d detected" % object_count
        
        #
        #Fill the hole and delete object witch touch the border. 
        #labeled_nuclei is modify after the function
        #Filter small object and split object
        #
        labeled_nuclei = fill_labeled_holes(labeled_nuclei)        
        labeled_nuclei = self.filter_on_border(labeled_nuclei)
        labeled_nuclei = self.filter_on_size(labeled_nuclei, object_count)         
        labeled_nuclei = self.split_object(labeled_nuclei)
        
        #
        #Edge detection of nuclei image and object are more separated 
        #
        labeled_nuclei_canny = skf.sobel(labeled_nuclei)       
        labeled_nuclei[labeled_nuclei_canny > 0] = 0
        labeled_nuclei = skr.minimum(labeled_nuclei.astype(np.uint16), skm.disk(3))
        
        image_collection.append((nuclei_image, "Original"))
        image_collection.append((labeled_nuclei, "Labelized image"))
        workspace.display_data.image_collection = image_collection

        #
        #Create a new object which will be add to the workspace
        #
        objects = cellprofiler.objects.Objects()
        objects.segmented = labeled_nuclei
        objects.parent_image = nuclei_image
        
        workspace.object_set.add_objects(objects, self.object_name.value)
Beispiel #12
0
def test_empty_selem():
    # check that min, max and mean returns zeros if structuring element is empty

    image = np.zeros((5, 5), dtype=np.uint16)
    out = np.zeros_like(image)
    mask = np.ones_like(image, dtype=np.uint8)
    res = np.zeros_like(image)
    image[2, 2] = 255
    image[2, 3] = 128
    image[1, 2] = 16

    elem = np.array([[0, 0, 0], [0, 0, 0]], dtype=np.uint8)

    rank.mean(image=image, selem=elem, out=out, mask=mask,
              shift_x=0, shift_y=0)
    assert_array_equal(res, out)
    rank.minimum(image=image, selem=elem, out=out, mask=mask,
                 shift_x=0, shift_y=0)
    assert_array_equal(res, out)
    rank.maximum(image=image, selem=elem, out=out, mask=mask,
                 shift_x=0, shift_y=0)
    assert_array_equal(res, out)
.. note::

    `skimage.dilate` and `skimage.erode` are equivalent filters (see below for
    comparison).

Here is an example of the classical morphological gray-level filters: opening,
closing and morphological gradient.

"""

from skimage.filter.rank import maximum, minimum, gradient

noisy_image = img_as_ubyte(data.camera())

closing = maximum(minimum(noisy_image, disk(5)), disk(5))
opening = minimum(maximum(noisy_image, disk(5)), disk(5))
grad = gradient(noisy_image, disk(5))

# display results
fig = plt.figure(figsize=[10, 7])

plt.subplot(2, 2, 1)
plt.imshow(noisy_image, cmap=plt.cm.gray)
plt.title('Original')
plt.axis('off')

plt.subplot(2, 2, 2)
plt.imshow(closing, cmap=plt.cm.gray)
plt.title('Gray-level closing')
plt.axis('off')
.. note::

    `skimage.dilate` and `skimage.erode` are equivalent filters (see below for
    comparison).

Here is an example of the classical morphological gray-level filters: opening,
closing and morphological gradient.

"""

from skimage.filter.rank import maximum, minimum, gradient

noisy_image = img_as_ubyte(data.camera())

closing = maximum(minimum(noisy_image, disk(5)), disk(5))
opening = minimum(maximum(noisy_image, disk(5)), disk(5))
grad = gradient(noisy_image, disk(5))

# display results
fig = plt.figure(figsize=[10, 7])

plt.subplot(2, 2, 1)
plt.imshow(noisy_image, cmap=plt.cm.gray)
plt.title('Original')
plt.axis('off')

plt.subplot(2, 2, 2)
plt.imshow(closing, cmap=plt.cm.gray)
plt.title('Gray-level closing')
plt.axis('off')
.. note::

    `skimage.dilate` and `skimage.erode` are equivalent filters (see below for
    comparison).

Here is an example of the classical morphological greylevel filters: opening,
closing and morphological gradient.

"""

from skimage.filter.rank import maximum, minimum, gradient

ima = data.camera()

closing = maximum(minimum(ima, disk(5)), disk(5))
opening = minimum(maximum(ima, disk(5)), disk(5))
grad = gradient(ima, disk(5))

# display results
fig = plt.figure(figsize=[10, 7])
plt.subplot(2, 2, 1)
plt.imshow(ima, cmap=plt.cm.gray)
plt.xlabel('original')
plt.subplot(2, 2, 2)
plt.imshow(closing, cmap=plt.cm.gray)
plt.xlabel('greylevel closing')
plt.subplot(2, 2, 3)
plt.imshow(opening, cmap=plt.cm.gray)
plt.xlabel('greylevel opening')
plt.subplot(2, 2, 4)
.. note::

    `skimage.dilate` and `skimage.erode` are equivalent filters (see below for
    comparison).

Here is an example of the classical morphological greylevel filters: opening,
closing and morphological gradient.

"""

from skimage.filter.rank import maximum, minimum, gradient

ima = data.camera()

closing = maximum(minimum(ima, disk(5)), disk(5))
opening = minimum(maximum(ima, disk(5)), disk(5))
grad = gradient(ima, disk(5))

# display results
fig = plt.figure(figsize=[10, 7])
plt.subplot(2, 2, 1)
plt.imshow(ima, cmap=plt.cm.gray)
plt.xlabel('original')
plt.subplot(2, 2, 2)
plt.imshow(closing, cmap=plt.cm.gray)
plt.xlabel('greylevel closing')
plt.subplot(2, 2, 3)
plt.imshow(opening, cmap=plt.cm.gray)
plt.xlabel('greylevel opening')
plt.subplot(2, 2, 4)
Beispiel #17
0
def processFile(f):
   
   # Handle DICOM
   if isdicom(f):
      ds = dicom.read_file(f)
      fname = f.rsplit('.', 1)[0]+'.tif' # make a tiff file under the same name to read from
      pil_dcm = get_dicom_PIL(ds)
      pil_dcm.save(fname)
   else:
      fname = f

   # Set output file name
   fname_out = f.rsplit('.', 1)[0]+"-out.jpg"

   # Open the image file for processing
   print "File to process: "+fname      
   origimg = cv2.imread(fname, cv2.CV_LOAD_IMAGE_GRAYSCALE)
      
   # Chop off the top of the image b/c there is often noncontributory artifact & make numpy arrays
   img = origimg[25:,:]
   imarray = np.array(img)
   
   imarraymarkup = imarray
   maskarray = np.zeros_like(imarray)
   contoursarray = np.zeros_like(imarray)
   onesarray = np.ones_like(imarray)
   
    # Store dimensions for subsequent calculcations
   max_imheight = maskarray.shape[0]
   max_imwidth = maskarray.shape[1]
   
   if DEBUG: print max_imwidth, max_imheight
    
   # Choose the minimum in the entire array as the threshold value b/c some mammograms have > 0 background which screws up the contour finding if based on zero or some arbitrary number
   ret,thresh = cv2.threshold(imarray,np.amin(imarray),255,cv2.THRESH_BINARY)
   contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    
   biggest_contour = []
   for n, contour in enumerate(contours):
      if len(contour) > len(biggest_contour):
         biggest_contour = contour

    # Get the lower most extent of the contour (biggest y-value)
   max_vals = np.argmax(biggest_contour, axis = 0)
   min_vals = np.argmin(biggest_contour, axis = 0)
    #print max_vals[0,1]
   bc_max_y = biggest_contour[max_vals[0,1],0,1] # get the biggest contour max y
   bc_min_y = biggest_contour[min_vals[0,1],0,1] # get the biggest contour min y
    #print "Biggest Contour Max Y:"
    #print bc_max_y
    #print "Biggest Contour Min Y:"
    #print bc_min_y
   
   cv2.drawContours(contoursarray,biggest_contour,-1,(255,255,255),15)            

    # Calculate R/L sidedness using centroid
   M = cv2.moments(biggest_contour)
   cx = int(M['m10']/M['m00'])
   cy = int(M['m01']/M['m00'])
   right_side = cx > max_imwidth/2
    
    # Plot the center of mass
   cv2.circle(contoursarray,(cx,cy),100,[255,0,255],-1)            

    # Approximate the breast
   epsilon = 0.001*cv2.arcLength(biggest_contour,True)
   approx = cv2.approxPolyDP(biggest_contour,epsilon,True)
            
    # Calculate the hull and convexity defects
   drawhull = cv2.convexHull(approx)
    #cv2.drawContours(contoursarray,drawhull,-1,(0,255,0),60)
   hull = cv2.convexHull(approx, returnPoints = False)
   defects = cv2.convexityDefects(approx,hull)
   
    # Plot the defects and find the most superior. Note: I think the superior and inferior ones have to be kept separate
    # Also make sure that these are one beyond a reasonable distance from the centroid (arbitrarily cdist_factor = 80%) to make sure that nipple-related defects don't interfere
   supdef_y = maskarray.shape[0]
   supdef_tuple = []
   
   cdist_factor = 0.80

   if defects is not None:
      for i in range(defects.shape[0]):
         s,e,f,d = defects[i,0]
         far = tuple(approx[f][0])
         if far[1] < (cy*cdist_factor) and far[1] < supdef_y:
            supdef_y = far[1]
            supdef_tuple = far
            cv2.circle(contoursarray,far,50,[255,0,255],-1)

    # Find lower defect if there is one
    # Considering adding if a lower one is at least greater than 1/2 the distance between the centroid and the lower most border of the contour (see IMGS_MLO/IM4010.tif)
   infdef_y = 0
   infdef_tuple = []
   if defects is not None:
      for i in range(defects.shape[0]):
         s,e,f,d = defects[i,0]
         far = tuple(approx[f][0])
         if far[1] > infdef_y and supdef_tuple: # cy + 3/4*(bc_max_y - cy) = (bc_max_y + cy)/2
            if (right_side and far[0] > supdef_tuple[0]) or (not right_side and far[0] < supdef_tuple[0]):
               infdef_y = far[1]
               infdef_tuple = far
               cv2.circle(contoursarray,far,50,[255,0,255],-1)

    # Try cropping contour beyond certain index; get indices of supdef/infdef tuples, and truncate vector beyond those indices
   cropped_contour = biggest_contour[:,:,:]
               
   if supdef_tuple:
      sup_idx = [i for i, v in enumerate(biggest_contour[:,0,:]) if v[0] == supdef_tuple[0] and v[1] == supdef_tuple[1]]
      if sup_idx:
         if right_side:
            cropped_contour = cropped_contour[sup_idx[0]:,:,:]
         else:
            cropped_contour = cropped_contour[:sup_idx[0],:,:]
            
   if infdef_tuple:
      inf_idx = [i for i, v in enumerate(cropped_contour[:,0,:]) if v[0] == infdef_tuple[0] and v[1] == infdef_tuple[1]]
      if inf_idx:
         if right_side:
            cropped_contour = cropped_contour[:inf_idx[0],:,:]
         else:
            cropped_contour = cropped_contour[inf_idx[0]:,:,:]
         
   if right_side:
      cropped_contour = cropped_contour[cropped_contour[:,0,1] != 1]
   else:
      cropped_contour = cropped_contour[cropped_contour[:,0,0] != 1]

    # Draw the cropped contour
    #cv2.drawContours(imarraymarkup,cropped_contour,-1,(255,255,0),30)
    #cv2.drawContours(imarraymarkup,biggest_contour,-1,(255,0,0),30)

    # Fill in the cropped polygon to mask
    #cv2.fillPoly(maskarray, pts = [cropped_contour], color=(255,255,255))
   cv2.fillPoly(maskarray, pts = [cropped_contour], color=(255,255,255))
    #maskarray = ~np.all(maskarray == 0, axis=1)a
    #print maskarray
    #maskarray[~np.all(maskarray == 0, axis=2)]

    # Threshold the cropped version
    #ret_otsu,thresh_otsu = cv2.threshold(imarray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

    # Multiply original image to the mask to get the cropped image
   imarray2 = imarray + onesarray
   imcrop_orig = cv2.bitwise_and(imarray2, maskarray)
    #cv2.drawContours(maskarray,biggest_contour,-1,(255,0,0),3)
    
   rankmin_out = rank.minimum(imcrop_orig, disk(20))
   thresh = mahotas.otsu(rankmin_out, ignore_zeros = True)

    # Draw thick black contour to eliminate the skin and nipple from the image
   cv2.drawContours(rankmin_out,cropped_contour,-1,(0,0,0),255) # 
    #cv2.drawContours(maskarray,cropped_contour,-1,(0,0,0),255) # 

    # Apply the thresholding to generate a new matrix and convert to int type
   otsubool_out = rankmin_out > thresh
   otsubinary_out = otsubool_out.astype('uint8')
   otsuint_out = otsubinary_out * 255

    # Crop out the fibroglandular tissue
    #print output2.shape, imarray2.shape, np.amax(output2), np.amax(imarray2), np.amax(maskarray)
   imcrop_fgt = cv2.bitwise_and(imarray2, otsuint_out) # both arrays are uint8 type

   segmented = maskarray > 0
   segmented = segmented.astype(int)
   segmented_sum = segmented.sum()
   otsubinary_sum = otsubinary_out.sum()
   
   density = (otsubinary_sum*100/segmented_sum).astype(int)
   
   if density < 25:
      dcat = 'Fatty'
   elif density < 50:
      dcat = 'Scattered'
   elif density < 75:
      dcat = 'Heterogenous'
   else:
      dcat = 'Extremely Dense'
        
   if right_side:
      side = 'Right'
   else:
      side = 'Left'

   if bc_min_y > 1:
      view = 'CC'
   else:
      view = 'MLO'
      
   avg = (imcrop_fgt.sum()/otsubinary_sum).astype(int)
   print side, view, otsubinary_sum, segmented_sum, density, dcat, avg, avg/np.amax(imcrop_fgt), np.amax(imcrop_fgt)
    
   # Create pil images
   pil1 = Image.fromarray(imarray2)
   pil2 = Image.fromarray(imcrop_fgt)
   pil3 = Image.fromarray(contoursarray)
   pil4 = Image.fromarray(maskarray)

   # Pasting images above to a pil background along with text. There's a lot of particular measurements sizing the fonts & pictures so that everything fits.  It's somewhat arbitrary with lots of trial and error, but basically everything is based off the resized width of the first image.  Images needed to be resized down b/c they were too high resolution for canvas.
   rf = 2 # rf = resize factor

   w1,h1 = pil1.size
   pil1_sm = pil1.resize((w1/rf,h1/rf))
   w1_sm,h1_sm = pil1_sm.size

   pil2_sm = pil2.resize((w1_sm,h1_sm))
   pil3_sm = pil3.resize((w1_sm,h1_sm))
   pil4_sm = pil4.resize((w1_sm,h1_sm))

   pil_backdrop = Image.new('L', (100+2*w1_sm,2*h1_sm+h1_sm/2), "white")

   pil_backdrop.paste(pil1_sm, (0,h1_sm/8))
   pil_backdrop.paste(pil2_sm, (100+w1_sm,h1_sm/8))
   pil_backdrop.paste(pil3_sm, (0,h1_sm/4+h1_sm))
   pil_backdrop.paste(pil4_sm, (100+w1_sm,h1_sm/4+h1_sm))

   font = ImageFont.truetype(FONT_PATH+"Arial.ttf",w1_sm/18)

   draw = ImageDraw.Draw(pil_backdrop)
   draw.text((0,0),"Original Image",0,font=font)
   draw.text((100+w1_sm,0),"Fibroglandular Tissue",0,font=font)
   draw.text((0,h1_sm+h1_sm/6),"Breast Contouring",0,font=font)
   draw.text((100+w1_sm,h1_sm+h1_sm/6),"Breast Segmentation",0,font=font)

   pil_backdrop.save(fname_out)
    
   return density, dcat, side, view