Ask Your Question

Revision history [back]

Train KNN classifier with several samples OpenCV Python

I am working on a logotype classifier/recognizer using Python 2.7.5 and OpenCV 2.4.8,

I have several images of the same logo but in different forms and presentations, I would like to train the classifier with that information and at the final recover the name of that logo regardless the form or presentation.

I would like to know how to train a KNN classifier using that information, I have the code that extracts the keypoints and descriptors using SURF, and I am storing that data directly on the hard disk.

def FeatureDetector(cvImage=None, filename=None):
  template = dict()
  hessian_threshold = 5000

  if(filename is not None):
    inputImage = cv.imread(filename)

  if(cvImage is not None):
    inputImage = cvImage

  imageGray = cv.cvtColor(inputImage, cv.COLOR_BGR2GRAY)

  detector = cv.SURF(hessian_threshold)
  keypoints, descriptors = detector.detectAndCompute(imageGray, None, useProvidedKeypoints = False)

  template["image"] = inputImage
  template["array"] = imageGray
  template["keypoints"] = keypoints
  template["descriptors"] = descriptors

  return template

def saveKeypoints(filename, keypoints):
  kArray = []

  for point in keypoints:
    keypoint = (point.pt, point.size, point.angle, point.response, point.octave, point.class_id)
    kArray.append(keypoint)

  with open(filename, "wb") as outputFile:
    pickle.dump(kArray, outputFile)

  return

def detection(logoName, extension, show=False):
  imagePath = PATHS["logos"] + logoName + "/"

  if(os.path.exists(imagePath)):
    count = 1
    while(True):
      filename = imagePath + str(count) + "." + extension

      if(not os.path.exists(filename)):
        print "[!] File '%s' not found, the end of sequence was reached"%(filename)
        break

      temp = FeatureDetector(filename = filename)

      saveKeypoints(PATHS["keypoints"] + inputName + "/" + str(count) + ".kp", temp["keypoints"])
      np.save(PATHS["descriptors"] + inputName + "/" + str(count) + ".npy", temp["descriptors"])
      np.save(PATHS["arrays"] + inputName + "/" + str(count) + ".npy", temp["array"])

      if(show):
        showFeatures(filename, temp)

      print "[O] Processed '%s'"%(filename)
      count += 1

  else:
    print "[X] Logo not found\n"

  return

Then, I have another script that load the data and trains the KNN but only with one form of a logo. I would like to train the classifier with all the forms of the logo, using all the keypoints and descriptors that I have and recover only one result.

def loadKeypoints(path):
  keypoints = []

  try:
    with open(PATHS["keypoints"] + path + ".kp", "rb") as inputFile:
      kArray = pickle.load(inputFile)

    for point in kArray:
      feature = cv.KeyPoint(
        x=point[0][0],
        y=point[0][1],
        _size=point[1],
        _angle=point[2],
        _response=point[3],
        _octave=point[4],
        _class_id=point[5]
      )

      keypoints.append(feature)      

  except:
    return False

  return keypoints


def loadSURF():
  global TEMPLATES, LOGOS

  for logo in LOGOS:
    TEMPLATES[logo] = list()
    count = 1
    while(True):
      path = "%s/%d"%(logo, count)

      keypoints = loadKeypoints(path)

      if(not keypoints):
        print "[!] Template for '%s' not found, the end of sequence was reached"%(path)
        break

      descriptors = np.load(PATHS["descriptors"] + path + ".npy")
      array = np.load(PATHS["arrays"] + path + ".npy")

      template = {
        "keypoints": keypoints,
        "descriptors": descriptors,
        "array": array
      }

      print "[O] Template loaded from %s"%(path)
      TEMPLATES[logo].append(template)
      count += 1

  return

def SURFCompare(temp, image):
  samples = temp["descriptors"]
  responses = np.arange(len(temp["keypoints"]), dtype=np.float32)

  knn = cv.KNearest()
  knn.train(samples, responses)

  for template in TEMPLATES:
    pattern = TEMPLATES[template]
    for t in pattern:
      for h, des in enumerate(t["descriptors"]):
        des = np.array(des,np.float32).reshape((1,128))
        retval, results, neigh_resp, dists = knn.find_nearest(des,1)
        res, dist = int(results[0][0]), dists[0][0]

        if dist < 0.1: # draw matched keypoints in red color
          color = (0,0,255)
          print template
        else:  # draw unmatched in blue color
          color = (255,0,0)

        #Draw matched key points on original image
        x,y = temp["keypoints"][res].pt
        center = (int(x),int(y))
        cv.circle(image,center,2,color,-1)

  return True

Is that possible?
Is the KNN classifier the best approaching or there are another better options? Also I am thinking on use a FLANN matcher.

I don't know if it is the best options because actually I'm only recongnize one logo in one form but I expect to have the possibility of recognize more than one logo in several forms each one.

Thanks in advance.