def process(options, args): trainSetFilename = args[0] inputImages = [line.strip() for line in open(trainSetFilename).readlines()] outputFilename = args[1] keepLimited = options.descriptorsPerImage if keepLimited < 0: # estimate a good number if options.codebookSize > 1024: keepLimited = 250000 // len(inputImages) else: keepLimited = 100000 // len(inputImages) # create one file to store output of software (f, tempFilename) = tempfile.mkstemp() os.close(f) print "Created temporary file:", tempFilename print "Keeping maximum of %d descriptors per image for clustering" % keepLimited startTime = time.time() clusterInput = [] for inputImage in inputImages: # extract features for this image cmdLine = "%s %s --keepLimited %d --outputFormat binary --output %s %s" % ( binarySoftware, inputImage, keepLimited, tempFilename, extractionConfig) returnCode = os.system(cmdLine) if returnCode != 0: raise Exception( "Error when executing '%s': command returned error" % cmdLine) (points, descriptors) = DescriptorIO.readDescriptors(tempFilename) if descriptors.size > 0: clusterInput.append(descriptors) os.remove(tempFilename) data = numpy.concatenate(clusterInput) print "Have cluster input (#descriptors, #dimensionality):", data.shape, "after", time.time( ) - startTime, "seconds" print "Starting k-means with %d iterations to find %d clusters" % ( options.iterations, options.codebookSize) clusters, perf = kmeans(data, options.codebookSize, iter=options.iterations) print "Best distance:", perf, "; shape:", clusters.shape, ";", time.time( ) - startTime, "seconds" DescriptorIO.writeBinaryDescriptors( outputFilename, numpy.array([[float(i)] for i in range(clusters.shape[0])]), clusters, "CODEBOOK")
def do_extraction(self): if not os.path.exists(self.extracted_descriptor_dir): os.makedirs(self.extracted_descriptor_dir) files_in_dir = os.listdir(self.image_dir) for f in files_in_dir: if f[-1] == "g": image_name = os.path.join(self.image_dir, f) temp_bin = os.path.join("data" , "tmp", "tmp.bin") colordescriptor_params = "--detector densesampling --ds_spacing 6 --ds_scales 1.6+2.4+3.2 --descriptor sift --outputFormat binary --output " colordescriptor_exe = os.path.join("data", "colorDescriptor", "colorDescriptor") exec_command = "{0} {1} {2} {3}".format(colordescriptor_exe, image_name, colordescriptor_params, temp_bin) os.system(exec_command) keypoints, descriptors = DescriptorIO.readDescriptors(temp_bin) fd = file(os.path.join(self.extracted_descriptor_dir, f[0:-4] + ".npy"), "wb") np.save(fd, descriptors) np.save(fd, keypoints)
def process(options, args): trainSetFilename = args[0] inputImages = [line.strip() for line in open(trainSetFilename).readlines()] outputFilename = args[1] keepLimited = options.descriptorsPerImage if keepLimited < 0: # estimate a good number if options.codebookSize > 1024: keepLimited = 250000 // len(inputImages) else: keepLimited = 100000 // len(inputImages) # create one file to store output of software (f, tempFilename) = tempfile.mkstemp() os.close(f) print "Created temporary file:", tempFilename print "Keeping maximum of %d descriptors per image for clustering" % keepLimited startTime = time.time() clusterInput = [] for inputImage in inputImages: # extract features for this image cmdLine = "%s %s --keepLimited %d --outputFormat binary --output %s %s" % (binarySoftware, inputImage, keepLimited, tempFilename, extractionConfig) returnCode = os.system(cmdLine) if returnCode != 0: raise Exception("Error when executing '%s': command returned error" % cmdLine) (points, descriptors) = DescriptorIO.readDescriptors(tempFilename) if descriptors.size > 0: clusterInput.append(descriptors) os.remove(tempFilename) data = numpy.concatenate(clusterInput) print "Have cluster input (#descriptors, #dimensionality):", data.shape, "after", time.time() - startTime, "seconds" print "Starting k-means with %d iterations to find %d clusters" % (options.iterations, options.codebookSize) clusters, perf = kmeans(data, options.codebookSize, iter=options.iterations) print "Best distance:", perf, "; shape:", clusters.shape, ";", time.time() - startTime, "seconds" DescriptorIO.writeBinaryDescriptors(outputFilename, numpy.array([[float(i)] for i in range(clusters.shape[0])]), clusters, "CODEBOOK")
# image. cmd = [cd_exe, img_filepath, '--output', tmp_path, # "harrislaplace" is another option here, but this can result in 0 # descriptors for an image, and is also slower. '--detector', 'densesampling', # '--detector', 'harrislaplace', '--ds_spacing', str(ds_spacing), '--descriptor', descriptor_type] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.communicate() # Info matrix consists of [x, y, scale, orientation, corner-ness] # - See colorDescriptor documentation for more information try: log.debug("Reading descriptors output") info, descriptors = DescriptorIO.readDescriptors(tmp_path) except IOError, ex: raise RuntimeError("ColorDescriptor failed to generate proper output " "file. See error log for details. (error: %s" % str(ex)) finally: os.remove(tmp_path) # Also error if the descriptor is empty if not descriptors.shape[1]: raise RuntimeError("Produced empty descriptor.") # Divides each row in the descriptors matrix with the row-wise sum. # - This results in histograms for relative frequencies instead of direct # bin counts. # - Adding float_info.min to row sums to prevent div-by-zero exception while
def generate_descriptors(cd_exe, img_filepath, descriptor_type, info_matrix_path, descr_matrix_path, limit_descriptors=None, recompute=False): """ Execute the given colorDescriptor executable, saving the generated info and descriptor matrices for the provided image to the provided file paths. Descriptor matrix is normalized into histograms of relative frequencies instead of histograms of raw bin counts. This does NOT return matrices directly due to memory concerns, especially in regards to multiprocessing as multiple copies of the matrix exist in the system, leading to excessive memory clogging. Matrices are saved in numpy binary format (.npy). ``numpy.load`` function should be used to load matrices back in. :raises ImportError: The required python module for colorDescriptor IO is not available. :raises RuntimeError: Failed to generate output files or matrices for the ' given input. :param cd_exe: ColorDescriptor executable to use :type cd_exe: str :param img_filepath: Path to the image file to process :type img_filepath: str :param descriptor_type: String type of descriptor to use from colorDescriptor. :type descriptor_type: str :param info_matrix_path: Path to where the computed information matrix for the given file should be saved. This will be saved as a numpy binary file (.npy). :type info_matrix_path: str :param descr_matrix_path: Path to where the computed descriptor matrix for the given file should be saved. This will be saved as a numpy binary file (.npy). :type descr_matrix_path: str :param limit_descriptors: Limit the number of descriptors generated if we were to produce more than the limit. If we exceed the limit, we randomly subsample down to the limit. :type limit_descriptors: int :param recompute: Force re-computation of descriptors for the given image file. This causes possible existing output files to be overwritten. :type recompute: bool :return: Shape information for info and descriptor matrices :rtype: ((int, int), (int, int)) """ if not has_colordescriptor_module(): raise ImportError("Cannot find the DescriptorIO module provided by " "ColorDescriptor. Read the README for dependencies!") log = logging.getLogger("ColorDescriptor::generate_descriptors{%s,%s}" % (descriptor_type, osp.basename(img_filepath))) if not recompute \ and osp.isfile(info_matrix_path) \ and osp.isfile(descr_matrix_path): # log.debug("Found existing matrix files, loading shapes.") return (numpy.load(info_matrix_path).shape, numpy.load(descr_matrix_path).shape) # Determine the spacing between sample points in the image. We want have at # least 50 sample points along the shortest side with a minimum of 6 pixels # distance between sample points. try: w, h = PIL.Image.open(img_filepath).size except IOError as ex: raise RuntimeError("Could not open image at filepath '%s': %s" % (img_filepath, str(ex))) ds_spacing = max(int(min(w, h) / 50.0), 6) log.debug("dense-sample spacing: %d", ds_spacing) tmp_fd, tmp_path = tempfile.mkstemp(prefix='colorDescriptor.') os.close(tmp_fd) log.debug("launching executable subprocess") # TODO: Perform harrislaplace detection method, if yields 0 descriptors, run # densesample method. When harrislaplace fails, this generally means # that there are no edge features in the image, e.g. a solid color # image. cmd = [ cd_exe, img_filepath, '--output', tmp_path, # "harrislaplace" is another option here, but this can result in 0 # descriptors for an image, and is also slower. '--detector', 'densesampling', # '--detector', 'harrislaplace', '--ds_spacing', str(ds_spacing), '--descriptor', descriptor_type ] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.communicate() # Info matrix consists of [x, y, scale, orientation, corner-ness] # - See colorDescriptor documentation for more information try: log.debug("Reading descriptors output") info, descriptors = DescriptorIO.readDescriptors(tmp_path) except IOError as ex: raise RuntimeError("ColorDescriptor failed to generate proper output " "file. See error log for details. (error: %s" % str(ex)) finally: os.remove(tmp_path) # Also error if the descriptor is empty if not descriptors.shape[1]: raise RuntimeError("Produced empty descriptor.") # Divides each row in the descriptors matrix with the row-wise sum. # - This results in histograms for relative frequencies instead of direct # bin counts. # - Adding float_info.min to row sums to prevent div-by-zero exception while # introducing minimal numerical error. # noinspection PyUnresolvedReferences log.debug("normalizing histogram into relative frequency") # noinspection PyUnresolvedReferences descriptors = descriptors / (numpy.matrix(descriptors).sum(axis=1) + sys.float_info.min).A # Randomly sample rows down to this count if what was generated exceeded the # limit. if limit_descriptors and info.shape[0] > limit_descriptors: idxs = numpy.random.permutation(numpy.arange( info.shape[0]))[:limit_descriptors] idxs = sorted(idxs) info = info[idxs, :] descriptors = descriptors[idxs, :] numpy.save(info_matrix_path, info) numpy.save(descr_matrix_path, descriptors) return info.shape, descriptors.shape
'--detector', 'densesampling', # '--detector', 'harrislaplace', '--ds_spacing', str(ds_spacing), '--descriptor', descriptor_type ] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.communicate() # Info matrix consists of [x, y, scale, orientation, corner-ness] # - See colorDescriptor documentation for more information try: log.debug("Reading descriptors output") info, descriptors = DescriptorIO.readDescriptors(tmp_path) except IOError, ex: raise RuntimeError("ColorDescriptor failed to generate proper output " "file. See error log for details. (error: %s" % str(ex)) finally: os.remove(tmp_path) # Also error if the descriptor is empty if not descriptors.shape[1]: raise RuntimeError("Produced empty descriptor.") # Divides each row in the descriptors matrix with the row-wise sum. # - This results in histograms for relative frequencies instead of direct # bin counts. # - Adding float_info.min to row sums to prevent div-by-zero exception while
def generate_descriptors(cd_exe, img_filepath, descriptor_type, info_matrix_path, descr_matrix_path, limit_descriptors=None, recompute=False): """ Execute the given colorDescriptor executable, saving the generated info and descriptor matrices for the provided image to the provided file paths. Descriptor matrix is normalized into histograms of relative frequencies instead of histograms of raw bin counts. This does NOT return matrices directly due to memory concerns, especially in regards to multiprocessing as multiple copies of the matrix exist in the system, leading to excessive memory clogging. Matrices are saved in numpy binary format (.npy). ``numpy.load`` function should be used to load matrices back in. :raises ImportError: The required python module for colorDescriptor IO is not available. :raises RuntimeError: Failed to generate output files or matrices for the ' given input. :param cd_exe: ColorDescriptor executable to use :type cd_exe: str :param img_filepath: Path to the image file to process :type img_filepath: str :param descriptor_type: String type of descriptor to use from colorDescriptor. :type descriptor_type: str :param info_matrix_path: Path to where the computed information matrix for the given file should be saved. This will be saved as a numpy binary file (.npy). :type info_matrix_path: str :param descr_matrix_path: Path to where the computed descriptor matrix for the given file should be saved. This will be saved as a numpy binary file (.npy). :type descr_matrix_path: str :param limit_descriptors: Limit the number of descriptors generated if we were to produce more than the limit. If we exceed the limit, we randomly subsample down to the limit. :type limit_descriptors: int :param recompute: Force re-computation of descriptors for the given image file. This causes possible existing output files to be overwritten. :type recompute: bool :return: Shape information for info and descriptor matrices :rtype: ((int, int), (int, int)) """ if not has_colordescriptor_module(): raise ImportError("Cannot find the DescriptorIO module provided by " "ColorDescriptor. Read the README for dependencies!") log = logging.getLogger("ColorDescriptor::generate_descriptors{%s,%s}" % (descriptor_type, osp.basename(img_filepath))) if not recompute \ and osp.isfile(info_matrix_path) \ and osp.isfile(descr_matrix_path): # log.debug("Found existing matrix files, loading shapes.") return (numpy.load(info_matrix_path).shape, numpy.load(descr_matrix_path).shape) # Determine the spacing between sample points in the image. We want have at # least 50 sample points along the shortest side with a minimum of 6 pixels # distance between sample points. try: w, h = PIL.Image.open(img_filepath).size except IOError as ex: raise RuntimeError("Could not open image at filepath '%s': %s" % (img_filepath, str(ex))) ds_spacing = max(int(min(w, h) / 50.0), 6) log.debug("dense-sample spacing: %d", ds_spacing) tmp_fd, tmp_path = tempfile.mkstemp(prefix='colorDescriptor.') os.close(tmp_fd) log.debug("launching executable subprocess") # TODO: Perform harrislaplace detection method, if yields 0 descriptors, run # densesample method. When harrislaplace fails, this generally means # that there are no edge features in the image, e.g. a solid color # image. cmd = [cd_exe, img_filepath, '--output', tmp_path, # "harrislaplace" is another option here, but this can result in 0 # descriptors for an image, and is also slower. '--detector', 'densesampling', # '--detector', 'harrislaplace', '--ds_spacing', str(ds_spacing), '--descriptor', descriptor_type] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.communicate() # Info matrix consists of [x, y, scale, orientation, corner-ness] # - See colorDescriptor documentation for more information try: log.debug("Reading descriptors output") info, descriptors = DescriptorIO.readDescriptors(tmp_path) except IOError as ex: raise RuntimeError("ColorDescriptor failed to generate proper output " "file. See error log for details. (error: %s" % str(ex)) finally: os.remove(tmp_path) # Also error if the descriptor is empty if not descriptors.shape[1]: raise RuntimeError("Produced empty descriptor.") # Divides each row in the descriptors matrix with the row-wise sum. # - This results in histograms for relative frequencies instead of direct # bin counts. # - Adding float_info.min to row sums to prevent div-by-zero exception while # introducing minimal numerical error. # noinspection PyUnresolvedReferences log.debug("normalizing histogram into relative frequency") # noinspection PyUnresolvedReferences descriptors = descriptors / (numpy.matrix(descriptors).sum(axis=1) + sys.float_info.min).A # Randomly sample rows down to this count if what was generated exceeded the # limit. if limit_descriptors and info.shape[0] > limit_descriptors: idxs = numpy.random.permutation(numpy.arange(info.shape[0])) idxs = sorted(idxs[:limit_descriptors]) info = info[idxs, :] descriptors = descriptors[idxs, :] numpy.save(info_matrix_path, info) numpy.save(descr_matrix_path, descriptors) return info.shape, descriptors.shape