def main(): print __doc__ parser = argparse.ArgumentParser(description='Test image segmentation') parser.add_argument('image', metavar='FILE', help='Input image') parser.add_argument('--max-size', metavar='N', type=float, help="Scale the input image down if its perimeter exceeds N. Default is no scaling.") args = parser.parse_args() img = cv2.imread(args.image) if img == None or img.size == 0: sys.stderr.write("Failed to read %s\n" % args.image) return -1 sys.stderr.write("Processing %s...\n" % args.image) # Scale the image down if its perimeter exceeds the maximum (if set). img = common.scale_max_perimeter(img, args.max_size) # Linear enhancement enhanced1 = ft.naik_murthy_linear(img) # Nonlinear enhancement using S-type function enhanced2a = ft.naik_murthy_nonlinear(enhanced1, ft.s_type_enhancement, 0, 3, 0.5, 2) enhanced2b = ft.naik_murthy_nonlinear(enhanced1, ft.s_type_enhancement, 0, 3, 1.5, 2) # Enhancement using histogram equalization sums = bgr_to_sums(img) # Range 0..(255*3-1) sums = cv2.normalize(sums, None, 0, 255, cv2.NORM_MINMAX) # Range 0..255 sums = cv2.equalizeHist(np.uint8(sums)) sums = cv2.normalize(np.float32(sums), None, 0, 3, cv2.NORM_MINMAX) # Range 0..3 enhanced3 = ft.naik_murthy_nonlinear(img, sums, fmap=True) # Display the image in a window. cv2.namedWindow('image') cv2.imshow('image', img) while True: k = cv2.waitKey(0) & 0xFF if k == ord('0'): cv2.imshow('image', img) elif k == ord('1'): cv2.imshow('image', enhanced1) elif k == ord('2'): cv2.imshow('image', enhanced2a) elif k == ord('w'): cv2.imshow('image', enhanced2b) elif k == ord('3'): cv2.imshow('image', enhanced3) elif k == 27: break cv2.destroyAllWindows() return 0
def _preprocess(self): if self.img == None: raise ValueError("No image loaded") if 'preprocess' not in self.params: return # Scale the image down if its perimeter exceeds the maximum (if set). perim = sum(self.img.shape[:2]) max_perim = getattr(self.params.preprocess, 'maximum_perimeter', None) if max_perim and perim > max_perim: logging.info("Scaling down...") rf = float(max_perim) / perim self.img = cv2.resize(self.img, None, fx=rf, fy=rf) # Perform color enhancement. color_enhancement = getattr(self.params.preprocess, 'color_enhancement', None) if color_enhancement: for method, args in vars(color_enhancement).iteritems(): if method == 'naik_murthy_linear': logging.info("Color enhancement...") self.img = ft.naik_murthy_linear(self.img) else: raise ValueError("Unknown color enhancement method '%s'" % method) # Perform segmentation. segmentation = getattr(self.params.preprocess, 'segmentation', None) if segmentation: logging.info("Segmenting...") iterations = getattr(segmentation, 'iterations', 5) margin = getattr(segmentation, 'margin', 1) output_folder = getattr(segmentation, 'output_folder', None) # Create a binary mask for the largest contour. self.mask = common.grabcut(self.img, iterations, None, margin) self.bin_mask = np.where((self.mask==cv2.GC_FGD) + (self.mask==cv2.GC_PR_FGD), 255, 0).astype('uint8') contour = ft.get_largest_contour(self.bin_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contour == None: raise ValueError("No contour found for binary image") self.bin_mask = np.zeros(self.img.shape[:2], dtype=np.uint8) cv2.drawContours(self.bin_mask, [contour], 0, 255, -1) # Save the masked image to the output folder. if output_folder and os.path.isdir(output_folder): img_masked = cv2.bitwise_and(self.img, self.img, mask=self.bin_mask) fname = os.path.basename(self.path) out_path = os.path.join(output_folder, fname) cv2.imwrite(out_path, img_masked)
def __preprocess(self): """Perform preprocessing steps as specified in the configurations. Preprocessing steps may be: * Resizing * Color correction * Segmentation This method is executed by :meth:`make`. """ if self.img is None: raise RuntimeError("No image is loaded") if 'preprocess' not in self.config: return # Scale the image down if its perimeter (width+height) exceeds the # maximum. If a ROI is set, use the perimeter of the ROI instead, or # else we might end up with a very small ROI. if self.roi: perim = sum(self.roi[2:4]) else: perim = sum(self.img.shape[:2]) rf = 1.0 max_perim = getattr(self.config.preprocess, 'maximum_perimeter', None) if max_perim and perim > max_perim: logging.info("Scaling down...") rf = float(max_perim) / perim self.img = cv2.resize(self.img, None, fx=rf, fy=rf) # Account for the resizing factor if a ROI is set. if self.roi: self.roi = [int(x*rf) for x in self.roi] self.roi = tuple(self.roi) # Perform color enhancement. color_enhancement = getattr(self.config.preprocess, 'color_enhancement', None) if color_enhancement: for method, args in vars(color_enhancement).iteritems(): if method == 'naik_murthy_linear': logging.info("Color enhancement...") self.img = ft.naik_murthy_linear(self.img) else: raise ConfigurationError("Unknown color enhancement "\ "method '%s'" % method) # Perform segmentation. try: segmentation = self.config.preprocess.segmentation.grabcut except: segmentation = {} if segmentation: logging.info("Segmenting...") iters = getattr(segmentation, 'iters', 5) margin = getattr(segmentation, 'margin', 1) output_folder = getattr(segmentation, 'output_folder', None) # Get the main contour. self.mask = self.__grabcut(self.img, iters, self.roi, margin) self.bin_mask = np.where((self.mask==cv2.GC_FGD) + \ (self.mask==cv2.GC_PR_FGD), 255, 0).astype('uint8') contour = ft.get_largest_contour(self.bin_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contour is None: raise ValueError("No contour found for binary image") # Create a binary mask of the main contour. self.bin_mask = np.zeros(self.img.shape[:2], dtype=np.uint8) cv2.drawContours(self.bin_mask, [contour], 0, 255, -1) # Save the masked image to the output folder. if output_folder: img_masked = cv2.bitwise_and(self.img, self.img, mask=self.bin_mask) out_path = os.path.join(output_folder, self.path) out_dir = os.path.dirname(out_path) if not os.path.isdir(out_dir): os.makedirs(out_dir) cv2.imwrite(out_path, img_masked)
def __preprocess(self): """Perform preprocessing steps as specified in the configurations. Preprocessing steps may be: * Resizing * Color correction * Segmentation or cropping This method is executed by :meth:`make`. """ if self.img is None: raise RuntimeError("No image is loaded") if 'preprocess' not in self.config: return # Scale the image down if its perimeter (width+height) exceeds the # maximum. If a ROI is set, use the perimeter of the ROI instead, or # else we might end up with a very small ROI. if self.roi: perim = sum(self.roi[2:4]) else: perim = sum(self.img.shape[:2]) rf = 1.0 max_perim = getattr(self.config.preprocess, 'maximum_perimeter', None) if max_perim and perim > max_perim: logging.info("Scaling down...") rf = float(max_perim) / perim self.img = cv2.resize(self.img, None, fx=rf, fy=rf) # Account for the resizing factor if a ROI is set. if self.roi: self.roi = [int(x * rf) for x in self.roi] self.roi = tuple(self.roi) # Perform color enhancement. color_enhancement = getattr(self.config.preprocess, 'color_enhancement', None) if color_enhancement: for method, args in vars(color_enhancement).iteritems(): if method == 'naik_murthy_linear': logging.info("Color enhancement...") self.img = ft.naik_murthy_linear(self.img) else: raise ConfigurationError("Unknown color enhancement "\ "method '%s'" % method) # Perform segmentation. try: segmentation = self.config.preprocess.segmentation.grabcut except: segmentation = {} if segmentation: logging.info("Segmenting...") iters = getattr(segmentation, 'iters', 5) margin = getattr(segmentation, 'margin', 1) output_folder = getattr(segmentation, 'output_folder', None) # Get the main contour. self.mask = self.__grabcut(self.img, iters, self.roi, margin) self.bin_mask = np.where((self.mask==cv2.GC_FGD) + \ (self.mask==cv2.GC_PR_FGD), 255, 0).astype('uint8') contour = ft.get_largest_contour(self.bin_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contour is None: raise ValueError("No contour found for binary image") # Create a binary mask of the main contour. self.bin_mask = np.zeros(self.img.shape[:2], dtype=np.uint8) cv2.drawContours(self.bin_mask, [contour], 0, 255, -1) # Save the masked image to the output folder. if output_folder: img_masked = cv2.bitwise_and(self.img, self.img, mask=self.bin_mask) out_path = os.path.join(output_folder, self.path) out_dir = os.path.dirname(out_path) if not os.path.isdir(out_dir): os.makedirs(out_dir) cv2.imwrite(out_path, img_masked) else: # Crop image in stead of segmenting. try: crop = self.config.preprocess.crop except: crop = {} if crop: logging.info("Cropping image...") roi_pix = getattr(crop, 'roi_pix', None) roi_frac = getattr(crop, 'roi_frac', None) if roi_pix: # roi_pix is like (x, y, w, h) in pixel units. if len(roi_pix) != 4: raise ValueError( "roi_pix must be a list of four integers.") for x in roi_pix: if not (isinstance(x, int) and x >= 0): raise ValueError( "roi_pix must be a (x, y, w, h) tuple " "of integers.") self.roi = roi_pix elif roi_frac: # roi_frac is like (x1, x2, y1, y2) in fractions # of total img size. if len(roi_frac) != 4: raise ValueError( "roi_frac must be a list of four floats.") for x in roi_frac: if not 0 <= x <= 1: raise ValueError( "roi_frac must be a (x1, x2, y1, y2) tuple, " "where the values are floats between 0 and 1.") if not (roi_frac[0] < roi_frac[1] and roi_frac[2] < roi_frac[3]): raise ValueError( "roi_frac must be a (x1, x2, y1, y2) tuple, " "where x1 < x2 and y1 < y2.") # Make ROI like (x, y, w, h). self.roi = (int(self.img.shape[1] * roi_frac[0]), int(self.img.shape[0] * roi_frac[2]), int(self.img.shape[1] * roi_frac[1]) - int(self.img.shape[1] * roi_frac[0]), int(self.img.shape[0] * roi_frac[3]) - int(self.img.shape[0] * roi_frac[2])) else: logging.warning("No ROI for cropping found. Proceed " "without cropping.") self.roi = (0, 0, self.img.shape[1], self.img.shape[0]) # Crop image to given ROI. self.img = self.img[self.roi[1]:self.roi[1] + self.roi[3], self.roi[0]:self.roi[0] + self.roi[2]]
def __preprocess(self): """Perform preprocessing steps as specified in the configurations. Preprocessing steps may be: * Resizing * Color correction * Segmentation or cropping This method is executed by :meth:`make`. """ if self.img is None: raise RuntimeError("No image is loaded") if 'preprocess' not in self.config: return # Scale the image down if its perimeter (width+height) exceeds the # maximum. If a ROI is set, use the perimeter of the ROI instead, or # else we might end up with a very small ROI. if self.roi: perim = sum(self.roi[2:4]) else: perim = sum(self.img.shape[:2]) rf = 1.0 max_perim = getattr(self.config.preprocess, 'maximum_perimeter', None) if max_perim and perim > max_perim: logging.info("Scaling down...") rf = float(max_perim) / perim self.img = cv2.resize(self.img, None, fx=rf, fy=rf) # Account for the resizing factor if a ROI is set. if self.roi: self.roi = [int(x*rf) for x in self.roi] self.roi = tuple(self.roi) # Perform color enhancement. color_enhancement = getattr(self.config.preprocess, 'color_enhancement', None) if color_enhancement: for method, args in vars(color_enhancement).iteritems(): if method == 'naik_murthy_linear': logging.info("Color enhancement...") self.img = ft.naik_murthy_linear(self.img) else: raise ConfigurationError("Unknown color enhancement "\ "method '%s'" % method) # Perform segmentation. try: segmentation = self.config.preprocess.segmentation.grabcut except: segmentation = {} if segmentation: logging.info("Segmenting...") iters = getattr(segmentation, 'iters', 5) margin = getattr(segmentation, 'margin', 1) output_folder = getattr(segmentation, 'output_folder', None) # Get the main contour. self.mask = self.__grabcut(self.img, iters, self.roi, margin) self.bin_mask = np.where((self.mask==cv2.GC_FGD) + \ (self.mask==cv2.GC_PR_FGD), 255, 0).astype('uint8') contour = ft.get_largest_contour(self.bin_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contour is None: raise ValueError("No contour found for binary image") # Create a binary mask of the main contour. self.bin_mask = np.zeros(self.img.shape[:2], dtype=np.uint8) cv2.drawContours(self.bin_mask, [contour], 0, 255, -1) # Save the masked image to the output folder. if output_folder: img_masked = cv2.bitwise_and(self.img, self.img, mask=self.bin_mask) out_path = os.path.join(output_folder, self.path) out_dir = os.path.dirname(out_path) if not os.path.isdir(out_dir): os.makedirs(out_dir) cv2.imwrite(out_path, img_masked) else: # Crop image in stead of segmenting. try: crop = self.config.preprocess.crop except: crop = {} if crop: logging.info("Cropping image...") roi_pix = getattr(crop, 'roi_pix', None) roi_frac = getattr(crop, 'roi_frac', None) if roi_pix: # roi_pix is like (x, y, w, h) in pixel units. if len(roi_pix) != 4: raise ValueError( "roi_pix must be a list of four integers.") for x in roi_pix: if not (isinstance(x, int) and x >= 0): raise ValueError( "roi_pix must be a (x, y, w, h) tuple " "of integers.") self.roi = roi_pix elif roi_frac: # roi_frac is like (x1, x2, y1, y2) in fractions # of total img size. if len(roi_frac) != 4: raise ValueError( "roi_frac must be a list of four floats.") for x in roi_frac: if not 0 <= x <= 1: raise ValueError( "roi_frac must be a (x1, x2, y1, y2) tuple, " "where the values are floats between 0 and 1.") if not (roi_frac[0] < roi_frac[1] and roi_frac[2] < roi_frac[3]): raise ValueError( "roi_frac must be a (x1, x2, y1, y2) tuple, " "where x1 < x2 and y1 < y2.") # Make ROI like (x, y, w, h). self.roi = (int(self.img.shape[1] * roi_frac[0]), int(self.img.shape[0] * roi_frac[2]), int(self.img.shape[1] * roi_frac[1]) - int(self.img.shape[1] * roi_frac[0]), int(self.img.shape[0] * roi_frac[3]) - int(self.img.shape[0] * roi_frac[2])) else: logging.warning("No ROI for cropping found. Proceed " "without cropping.") self.roi = (0, 0, self.img.shape[1], self.img.shape[0]) # Crop image to given ROI. self.img = self.img[self.roi[1]: self.roi[1] + self.roi[3], self.roi[0]: self.roi[0] + self.roi[2]]