title: 10 Pin Bowling score capture
body: <p>I want to use OCR to capture the bowling scores from the monitor at the lances.  I had a look at <a href="https://stackoverflow.com/questions/10196198/how-to-remove-convexity-defects-in-a-sudoku-square/11366549#11366549">this sudoku solver</a>, as I think its pretty similar - numbers and grids right?  It has trouble finding the horizontal lines.  Has anyone got any tips for pre-processing this image to make it easier to detect the lines (or numbers!).  Also any tips for how to deal with the split (the orange ellipse around some of the 8's int he image)?</p>
  
  <p>So far I have got the outline of the score area and cropped it.</p>
  
  <pre><code>import matplotlib
  matplotlib.use('TkAgg')
  from skimage import io
  import numpy as np
  import matplotlib.pyplot as plt
  from skimage import measure
  from skimage.color import rgb2gray
  # import pytesseract
  from matplotlib.path import Path
  from qhd import *
  
  
  def polygonArea(poly):
      """
      Return area of an unclosed polygon.
  
      :see: https://stackoverflow.com/a/451482
      :param poly: (n,2)-array
      """
      # we need a plain list for the following operations
      if isinstance(poly, np.ndarray):
          poly = poly.tolist()
      segments = zip(poly, poly[1:] + [poly[0]])
      return 0.5 * abs(sum(x0*y1 - x1*y0
                           for ((x0, y0), (x1, y1)) in segments))
  
  filename = 'good.jpg'
  image = io.imread(filename)
  image = rgb2gray(image)
  
  # Find contours at a constant value of 0.8
  contours = measure.find_contours(image, 0.4)
  
  # Display the image and plot all contours found
  fig, ax = plt.subplots()
  
  c = 0
  biggest = None
  biggest_size = 0
  
  for n, contour in enumerate(contours):
      curr_size = polygonArea(contour)
      if  curr_size &gt; biggest_size:
          biggest = contour
          biggest_size = curr_size
  
  biggest = qhull2D(biggest)
  
  
  # Approximate that so we just get a rectangle.
  biggest = measure.approximate_polygon(biggest, 500)
  
  # vertices of the cropping polygon
  yc = biggest[:,0]
  xc = biggest[:,1]
  xycrop = np.vstack((xc, yc)).T
  
  # xy coordinates for each pixel in the image
  nr, nc = image.shape
  ygrid, xgrid = np.mgrid[:nr, :nc]
  xypix = np.vstack((xgrid.ravel(), ygrid.ravel())).T
  
  # construct a Path from the vertices
  pth = Path(xycrop, closed=False)
  
  # test which pixels fall within the path
  mask = pth.contains_points(xypix)
  
  # reshape to the same size as the image
  mask = mask.reshape(image.shape)
  
  # create a masked array
  masked = np.ma.masked_array(image, ~mask)
  
  # if you want to get rid of the blank space above and below the cropped
  # region, use the min and max x, y values of the cropping polygon:
  
  xmin, xmax = int(xc.min()), int(np.ceil(xc.max()))
  ymin, ymax = int(yc.min()), int(np.ceil(yc.max()))
  trimmed = masked[ymin:ymax, xmin:xmax]
  
  plt.imshow(trimmed, cmap=plt.cm.gray), plt.title('trimmed')
  plt.show()
  </code></pre>
  
  <p><a href="https://imgur.com/LijB85I" rel="nofollow">https://imgur.com/LijB85I</a> is an example of how the score is displayed.</p>