Exemple #1
0
def imshow(im, windowName='Image', histogram=False, bitDepth=8, dpi=128.5):

   # Determine the numnber of grey levels
   numberLevels = 2**bitDepth

   # Normalize the image so that it falls in the range [0, 1]
   normalizedImage = (im / float(numberLevels-1)).astype(numpy.float32)

   # Reverse the channel order (BGR to RGB) for color images (assumption is
   # that OpenCV-style color images are provided)
   if len(im.shape) == 3:
      normalizedImage = cv2.cvtColor(normalizedImage, cv2.COLOR_BGR2RGB)

   # Determine the current screen size and set the figure size appropriately
   scale = 0.85
   screenSize = hardware.get_screen_size(dpi=dpi)
   if histogram:
      figureSize = [screenSize[3]*scale, screenSize[2]*scale]
   else:
      figureSize = [screenSize[2]*scale, screenSize[2]*scale]

   # Create a Matplotlib figure with the given title and a canvas to contain
   # this figure
   figure = matplotlib.pyplot.figure(windowName,
                                     figsize=[figureSize[0], 
                                              figureSize[1]])
   canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(figure)

   # Add one or two subplot axes to the figure depending on whether or not
   # the histogram is to be displayed
   if histogram:
      figureRows = 2
      figureCols = 1
      axes1 = figure.add_subplot(figureRows, figureCols, 1)
      axes2 = figure.add_subplot(figureRows, figureCols, 2)
   else:
      figureRows = 1
      figureCols = 1
      axes1 = figure.add_subplot(figureRows, figureCols, 1)

   # Add the image and the histogram (if requested) to the figure
   if len(im.shape) == 2:
      axes1.imshow(normalizedImage, cmap=matplotlib.cm.Greys_r)
   else:
      axes1.imshow(normalizedImage)
   axes1.axis('off')

   if histogram:
      h, pdf, cdf = ipcv.histogram(im, maxCount=numberLevels-1)
      axes2.set_xlim([0, numberLevels-1])
      axes2.set_xlabel('DC')
      axes2.set_ylabel('PDF')
      if len(h) == 1:
         axes2.plot(range(numberLevels), pdf[0], 'k')
      else:
         for band in range(len(h)):
            axes2.plot(range(numberLevels), pdf[band])

   # Display the figure to the screen
   matplotlib.pyplot.show()
def histogram_enhancement(im, etype='linear2', target=None, maxCount=255):
	"""
	Title: histogram_enhancement
	Author: Molly Hill, [email protected]
	Description:
		Returns given image quantized at set number of levels, using either a uniform or IGS method.
	Attributes:
		im - ndarray, can be grayscale or color of any size
		etype - enhancement type, of the following options:
			    - 'linearX' where X is an integer percent of the area to be
			       clipped/crushed with contrast increas
			    - 'match' where the image is to be matched to a provided
			       target image or PDF
			    - 'equalize' where the image's histogram is to be spread
			       equally across digital count
		target - if etype = 'match', then target must be provided as either an
			 image (3D array) or PDF (1D array)
		maxCount - maximum code value of pixel; must be positive integer
	Requires:
		histogram.py, author: Carl Salvaggio
		dimensions.py, author: Carl Salvaggio
	"""

	if maxCount <= 0 or type(maxCount) is not int:
		msg = "Specified maximum digital count must be a positive integer."
		raise ValueError(msg)
	if type(im) is not numpy.ndarray:
		msg = "Specified image type must be ndarray."
		raise TypeError(msg)
	if etype[:6] != 'linear' and etype != 'match' and etype != 'equalize':
		msg = "Enhancement types available are linear, match, and equalize. Defaulting to linear2."
		print(msg)
	if etype == 'match':
		if type(target) == None:
			etype = 'equalize'
			msg = "If using match, target must be provided."
			print(msg)
		elif target.ndim !=1 and target.ndim !=2:
			print(target.ndim)
			msg = "Provided target must be PDF (1-D array) or image (3-D array)"
			raise TypeError(msg)

	enhIm = numpy.copy(im)
	srcCDF = ipcv.histogram(enhIm)[2]
	DCout = []
	tgtCDF = []
	tgtPDF = target
	
	if etype == 'match' or etype == 'equalize':
		if etype == 'match' and target.ndim != 1: #is image
			tgtCDF = ipcv.histogram(target)[2][0] #create CDF of target, currently does red channel if color
		else: #equalize or PDF passed in as target for matching
			if etype == 'equalize':
				tgtPDF = numpy.ones(maxCount+1)/(maxCount+1)
			tgtCDF = numpy.cumsum(tgtPDF) #convert PDF to CDF

		for i in range(ipcv.dimensions(srcCDF)[1]): #createLUT
			difference = numpy.fabs(numpy.subtract(tgtCDF,srcCDF[0][i])) #red channel only
			DCout.extend([int(maxCount*tgtCDF[numpy.argmin(difference)])])
		for j in range(im.size): #apply LUT
			enhIm.flat[j] = DCout[enhIm.flat[j]] #uses original code value to assign new output from LUT

	else: #linear
		pct = (int(etype[6:])/2) / 100 #extract percent from etype and halve
		difference = numpy.fabs(numpy.subtract(srcCDF[0],pct))
		DCmin = numpy.argmin(difference)
		difference = numpy.fabs(numpy.subtract(srcCDF[0],(1-pct)))
		DCmax = numpy.argmin(difference)

		slope = (maxCount+1)/(DCmax-DCmin)
		intercept = -slope * DCmin
		
		for j in range(enhIm.size):
			px = enhIm.flat[j]
			if px >= DCmax:
				px = maxCount
			elif px <= DCmin:
				px = 0
			else:
				px = slope * px + intercept
			enhIm.flat[j] = int(px)

	return enhIm
Exemple #3
0
    # A greyscale test image
    filename = 'crowd.jpg'
    # A 3-channel color test image
    filename = 'lenna.tif'

    im = cv2.imread(filename, cv2.IMREAD_UNCHANGED)
    print('Data type = {0}'.format(type(im)))
    print('Image shape = {0}'.format(im.shape))
    print('Image size = {0}'.format(im.size))
    
    dataType = str(im.dtype)
    imType = {'uint8':8, 'uint16':16, 'uint32':32}

    startTime = time.time()
    h, pdf, cdf = ipcv.histogram(im, bitDepth=imType[dataType])
    print('Elasped time = {0} [s]'.format(time.time() - startTime))

# The follow will produce a figure containing color-coded plots of the 
# computed histogram, probability function (PDF), and cumulative density
# function (CDF)

    import matplotlib.pyplot
    import matplotlib.backends.backend_agg
    
    maxCount = 2**imType[dataType]
    bins = list(range(maxCount))

    figure = matplotlib.pyplot.figure('Histogram')
    canvas = matplotlib.backends.backend_agg.FigureCanvas(figure)
    
    import cv2
    import ipcv
    import time

    # A greyscale test image
    #filename = 'crowd.jpg'
    # A 3-channel color test image
    filename = 'lenna.tiff'

    im = cv2.imread(filename, cv2.IMREAD_UNCHANGED)
    print('Data type = {0}'.format(type(im)))
    print('Image shape = {0}'.format(im.shape))
    print('Image size = {0}'.format(im.size))

    startTime = time.time()
    h, pdf, cdf = ipcv.histogram(im)
    print('Elapsed time = {0} [s]'.format(time.time() - startTime))

    Max = range(256)

    if len(im.shape) == 3:
        [histR, histG, histB] = h
        [pdfR, pdfG, pdfB] = pdf
        [cdfR, cdfG, cdfB] = cdf

        matplotlib.pyplot.figure(1)

        matplotlib.pyplot.subplot(3, 1, 1)
        matplotlib.pyplot.ylabel('number of pixels')
        matplotlib.pyplot.xlabel('Digital Count')
        matplotlib.pyplot.plot(Max, histR, 'r-')
def histogram_enhancement(img,
                          etype='linear2',
                          target=None,
                          maxCount=255,
                          pool=False):
    """
	:NAME:
		histogram_enchancement

	:PURPOSE:
		This method modifies an image using basic histogram enhancement techniques:
			linear -- removes removes extranesous pixels on outer edge of histogram and stretches
				histogram to fill entire DC range
			equalization -- a technique to even out peaks on the histogram and product a near-flat
				histogram curve
			match -- modifies an image such that it's pixel distribution mimics that of a target 
				image or distribution



	:CATEGORY:
		ipcv -- histogram enchancement tool

	:CALLING SEQUENCE:
		quantizedImage = histogram_enchancement(img,\
											etype=etype,\
											target=targer,\
											maxCount = maxCount,\
											pool = pool)


	:INPUTS:
		img
			[numpy.ndarray]	input image
		etype
			[string] type of histogram enhancement to perform
		target
			[numpy.ndarray] target image or distribution using in histogram matching
		maxCount
			[int] the largest possible DC value in the image
		pool
			[boolean] whether or not to pool all colors into one cdf or loop by band 
					

	:RETURN VALUE:
		a numpy array containing the enhanced image

	:SIDE EFFECTS:
		removes possibly pertinent data in an image

	:ERROR CHECKING:
		ValueError
		TypeError

	:REQUIRES:
		numpy
		sys.exc_info
		os.path.split

	:MODIFICATION HISTORY:
		Engineer:	Jeff Maggio
		original:	09/09/16

	"""

    #ERROR CHECKING
    if etype == "match":
        if (isinstance(target, np.ndarray) == False):
            print(
                "-------------------------------------------------------------------"
            )
            print(
                "input 'target' must by a valid numpy.ndarray, currently {0}".
                format(type(target)))
            print(
                "-------------------------------------------------------------------"
            )
            print("raising TypeError...")
            raise TypeError

    if isinstance(maxCount, int) == False:
        print(
            "-------------------------------------------------------------------"
        )
        print("input 'maxCount' must be an int type, currently is {0}".format(
            type(target)))
        print(
            "-------------------------------------------------------------------"
        )
    elif maxCount < 0:
        print(
            "-------------------------------------------------------------------"
        )
        print("maxCount must be greater than 0, currently is {0}".format(
            maxCount))
        print(
            "-------------------------------------------------------------------"
        )

    if isinstance(img, np.ndarray) == True:
        img = img.reshape(img.shape[0], img.shape[1], 1) if (len(img.shape)
                                                             == 2) else img
        bands = img.shape[2]

    if isinstance(target, np.ndarray) == True:
        target = target.reshape(target.shape[0], target.shape[1], 1) if (len(
            target.shape) == 2) else target

    if etype == "match":
        if (len(target.shape) != 1) and (target.shape[2] != img.shape[2]):
            print(
                "-------------------------------------------------------------------"
            )
            print(
                "original and target images must both be of the same type (grayscale or color"
            )
            print("raising TypeError...")
            print(
                "-------------------------------------------------------------------"
            )
            raise TypeError

    #BEGIN ACTUAL WORK
    try:
        #2 is index of cdf from return tuple

        if "linear" in etype:

            for band in range(bands):

                #cdf is recalculated by band
                cdf = ipcv.histogram(img=img,channels=band,histSize=(maxCount+1),\
                 ranges=[0,maxCount+1],returnType=1)[2]

                # generating components of the line
                lowerBound = (float(etype.replace("linear", "")) / 200.0
                              )  #1/2 input on each side
                upperbound = (1 - lowerBound)
                dcLow = np.where(cdf >= lowerBound)[0][0]
                dcHigh = np.where(cdf <= upperbound)[0][-1]
                m = (maxCount / (dcHigh - dcLow))
                b = maxCount - (m * dcHigh)

                #generating the lookup table by applying a linear transform
                LUT = (m * np.arange(maxCount + 1)) + b
                LUT = np.clip(LUT, 0, 255)
                print(img[:, :, band].shape)
                img[:, :, band] = LUT[img[:, :, band]]

        elif etype == 'equalize':

            for band in range(bands):
                cdf = ipcv.histogram(img=img,channels=band,histSize=(maxCount+1),\
                 ranges=[0,maxCount+1],returnType=1)[2]

                LUT = (cdf * maxCount).flatten()
                print(LUT.shape)
                img[:, :, band] = LUT[img[:, :, band]]

        elif etype == "match":
            #Generating the target CDFs
            tCdf = []
            if len(target.shape) == 1:
                for band in range(bands):
                    tCdf.append(np.cumsum(target))
            else:
                for band in range(bands):
                    tCdf.append(ipcv.histogram(img=target,channels=band,histSize=(maxCount+1),\
                     ranges=[0,maxCount+1],returnType=1)[2]) #only return the cdf here

            for band in range(bands):
                cdf = ipcv.histogram(img=img,channels=band,histSize=(maxCount+1),\
                 ranges=[0,maxCount+1],returnType=1)[2]

                LUT = np.zeros(maxCount + 1)
                index = 0
                for percentage in cdf:
                    upperValues = np.where(tCdf[band] >= percentage)
                    if upperValues[0].size != 0:
                        dc = upperValues[0][0]
                    else:
                        dc = 0
                    LUT[index] = dc
                    index += 1

                img[:, :, band] = LUT[img[:, :, band]]

        return img.astype(np.uint8)

    except Exception as e:
        print(
            "==================================================================="
        )
        exc_type, exc_obj, exc_tb = exc_info()
        fname = split(exc_tb.tb_frame.f_code.co_filename)[1]
        print("\nfile: {0}\n\nline: {1} \n\n{2}\n".format(
            fname, exc_tb.tb_lineno, e))
        print(
            "==================================================================="
        )
Exemple #6
0
def otsu_threshold(img, maxCount=255, verbose=False):
	"""
	:NAME:
		otsu_threshold

	:PURPOSE:
		this method generates a binary thresholded image based off of 
		Otsu's class discrimination method

	:CATEGORY:
		ipcv -- object recognition and thresholding tool

	:CALLING SEQUENCE:
		quantizedImage = quantize(img = inputImage,\
								 maxCount = max display level\
								 verbose = true or false)

	:INPUTS:
		img
			[numpy.ndarray]	input image to be quanitized
		maxCount
			[int] maximum pixel value in the output array
		verbose
			[boolean] whether or not to graph the histogram 

	:RETURN VALUE:
		tuple containing:
			returnTuple[0] -- binary numpy.array of the same shape as the input image
			returnTuple[1] -- threshold determined by otsu's method


	:ERROR CHECKING:
		TypeError
		ValueError
		RuntimeError

	:REQUIRES:
		np
		sys.exc_info
		os.path.split
		ipcv

	:MODIFICATION HISTORY:
		Engineer:	Jeff Maggio
		08/25/16:	otsu code

	"""
######################  BEGIN ERROR CHECKING  #######################
	if isinstance(img,np.ndarray) == True:
		dims = ipcv.dimensions(img,"dictionary")

		if dims["bands"] == 1:

			if len(img.shape) == 3:
				#making the array two dimensional if it only has 1 band 
				img = img.reshape(dims['rows'],dims['cols'])

		else:
			print("")
			print("input 'img' must be grayscale or single-banded")
			print("")
			raise RuntimeError

	else:
		print("")
		print("input 'img' must be a valid 2 dimensional numpy array, currently {0}".format(type(img)))
		print("")
		raise TypeError

	if isinstance(maxCount,int) == False:
		print("")
		print("input 'maxCount' must be an int, currently {0}".format(type(maxCount)))
		print("")
		raise TypeError
	elif maxCount <= 0:
		print("")
		print("input 'maxCount' must be greater than zero")
		print("")
		raise ValueError

	if isinstance(verbose,bool) == False:
		print("")
		print("input 'verbose' must be integer boolean , currently {0}".format(verbose))
		print("")
		raise TypeError


######################  END ERROR CHECKING  #######################

	try:

		numberCounts = maxCount + 1
		#generating the pdf and cdf
		hist,pdf,cdf = ipcv.histogram(img,histSize=numberCounts,ranges=[0,numberCounts])
		
		meanLevelArray = np.cumsum( np.arange(0,numberCounts) * pdf )
		muTotal = meanLevelArray[-1]

		sigmaSquaredBValues = np.zeros(numberCounts)
		startingK = np.where(cdf>0.0)[0][0]
		endingK = np.where(cdf<1.0)[0][-1]

		for k in range(startingK, endingK):
			muK = meanLevelArray[k]
			omegaK = cdf[k]
			sigmaSquaredB = ( ( (muTotal * omegaK) - muK )**2 ) / ( omegaK * (1-omegaK) )
			sigmaSquaredBValues[k] = sigmaSquaredB

		threshold = np.argmax(sigmaSquaredBValues)

		LUT = np.zeros( numberCounts )
		LUT[threshold+1:] = 1

		img = LUT[img]

		if verbose == True:
			values = (pdf,)
			colors = ('r',)
			filename = "image_pdf_wOtsu.eps"
			thresholdMarker = (threshold,)
			labels = ("pdf",)
			graph = ipcv.quickplot(values,colors,labels,filename=filename,verticalMarkers=thresholdMarker,\
				xLabel="Digital Counts",yLabel="probability",display=False)
			graph.annotate("otsu's Threshold", xy=(threshold, .01), xytext=(3, 1.5),arrowprops=dict(facecolor='black', shrink=0.05))
			graph.show()

		return img.astype(np.uint8), threshold


	except Exception as e:
		print("===============================================================")
		exc_type, exc_obj, tb = exc_info()
		fname = split(tb.tb_frame.f_code.co_filename)[1]
		print("\r\nfile: {0}\r\n\r\nline: {1} \r\n\r\n{2}\r\n\r\n".format(fname,tb.tb_lineno,exc_obj,e))
		print("===============================================================")
def otsu_threshold(im, maxCount=255, verbose=False):
    """
	Title: otsu_threshold
	Author: Molly Hill, [email protected]
	Description:
		Finds threshold for foreground/background in given image
	Returns:
		matte - binary image indicating areas above/below threshold
		kOpt - optimum threshold for given image
	Attributes:
		im - source image; ndarray, must be grayscale
		maxCount - maximum code value of pixel; must be positive integer
		verbose - if True, plots histogram of image, marked with optimum threshold
	Requires:
		histogram.py, author: Carl Salvaggio
	"""

    if maxCount <= 0 or type(maxCount) is not int:
        msg = "Specified maximum digital count must be a positive integer."
        raise ValueError(msg)
    if type(im) is not numpy.ndarray:
        msg = "Specified image type must be ndarray."
        raise TypeError(msg)
    if type(verbose) is not bool:
        msg = "Verbose must be a boolean. Defaulting to False."
        print(msg)

    #initialize variables
    srcIm = numpy.copy(im)
    histo = ipcv.histogram(srcIm)[0]
    srcPDF = ipcv.histogram(srcIm)[1][0]
    matte = []
    stdDev = []
    kOpt = 0
    firstMtot = []

    indices = numpy.arange(maxCount + 1)
    for i in range(numpy.size(indices)):
        firstMtot.extend([srcPDF[i] * indices[i]
                          ])  #pre-sum first moment across image
    meanLvl = numpy.sum(firstMtot)  #mean level of image

    for k in range(0, maxCount):
        zeroM = numpy.sum(srcPDF[0:k])  #zero moment
        if zeroM == 0 or zeroM == 1:
            stdDev.extend([0])
        else:
            firstM = numpy.sum(firstMtot[:k])  #first moment up to k
            stdDev.extend([
                (((meanLvl * zeroM) - firstM)**2) // (zeroM * (1 - zeroM))
            ])
    kOpt = numpy.argmax(stdDev) + 1

    matte = numpy.uint8(1 *
                        (im >= kOpt))  #get as Booleans and convert to integers

    if verbose == True:  #plot histogram and threshold
        #NOTE THIS SLOWS EVERYTHING DOWN BY A LOT
        matplotlib.pyplot.plot(indices, histo[0])
        matplotlib.pyplot.ylabel('Number of Pixels')
        matplotlib.pyplot.xlabel('Digital Count')
        matplotlib.pyplot.ylim([0, max(histo[0])])
        matplotlib.pyplot.xlim([0, maxCount])
        matplotlib.pyplot.axvline(x=kOpt,
                                  label='Threshold' + str(kOpt),
                                  color='r')
        matplotlib.pyplot.show()

    return matte, kOpt