Question

I have this image with boxes containing letters, like this:

Original

I have been able to crop out each box., like this:

Picture of a cropped box containing a letter

Now to my question. How can i crop out the letters only from each box? The desired result looks like this

desired result

I would like to use findContours but I am not really sure of how to achieve this since it will detect the noise and everything around as well.

Was it helpful?

Solution

Approach I suggest the following approach according to this fact that you can extract the box. If you are give the box follow the steps, I think that would work:

  1. Find the center of image
  2. Find the contours in the image - those can be candidates
  3. Find the bounding rectangle of each contour
  4. Find the center of each bounding rectangle
  5. Find the distance of each bounding rectangle from the center of image
  6. Find the minimum distance - your answer

Note: There is a var named pad which control the padding of the result figure! Do this for all your boxes. I hope that will help!

Good Luck :)


Python Code

# reading image in grayscale
image = cv2.imread('testing2.jpg',cv2.CV_LOAD_IMAGE_GRAYSCALE)
# thresholding to get a binary one
ret, image = cv2.threshold(image, 100,255,cv2.THRESH_BINARY_INV)
# finding the center of image
image_center = (image.shape[0]/2, image.shape[1]/2)

if image is None:
    print 'can not read the image data'
# finding image contours
contours, hier = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# finding distance of each contour from the center of image
d_min = 1000
for contour in contours:
    # finding bounding rect
    rect = cv2.boundingRect(contour)
    # skipping the outliers
    if rect[3] > image.shape[1]/2 and rect[2] > image.shape[0]/2:
        continue
    pt1 = (rect[0], rect[1])
    # finding the center of bounding rect-digit
    c = (rect[0]+rect[2]*1/2, rect[1]+rect[3]*1/2)
    d = np.sqrt((c[0] - image_center[0])**2 + (c[1]-image_center[1])**2)
    # finding the minimum distance from the center
    if d < d_min:
        d_min = d
        rect_min = [pt1, (rect[2],rect[3])]
# fetching the image with desired padding
pad = 5
result = image[rect_min[0][1]-pad:rect_min[0][1]+rect_min[1][1]+pad, rect_min[0][0]-pad:rect_min[0][0]+rect_min[1][0]+pad]

plt.imshow(result*255, 'gray')
plt.show()

Java Code

    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    // reading image 
    Mat image = Highgui.imread(".\\testing2.jpg", Highgui.CV_LOAD_IMAGE_GRAYSCALE);
    // clone the image 
    Mat original = image.clone();
    // thresholding the image to make a binary image
    Imgproc.threshold(image, image, 100, 128, Imgproc.THRESH_BINARY_INV);
    // find the center of the image
    double[] centers = {(double)image.width()/2, (double)image.height()/2};
    Point image_center = new Point(centers);

    // finding the contours
    ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
    Mat hierarchy = new Mat();
    Imgproc.findContours(image, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

    // finding best bounding rectangle for a contour whose distance is closer to the image center that other ones
    double d_min = Double.MAX_VALUE;
    Rect rect_min = new Rect();
    for (MatOfPoint contour : contours) {
        Rect rec = Imgproc.boundingRect(contour);
        // find the best candidates
        if (rec.height > image.height()/2 & rec.width > image.width()/2)            
            continue;
        Point pt1 = new Point((double)rec.x, (double)rec.y);
        Point center = new Point(rec.x+(double)(rec.width)/2, rec.y + (double)(rec.height)/2);
        double d = Math.sqrt(Math.pow((double)(pt1.x-image_center.x),2) + Math.pow((double)(pt1.y -image_center.y), 2));            
        if (d < d_min)
        {
            d_min = d;
            rect_min = rec;
        }                   
    }
    // slicing the image for result region
    int pad = 5;        
    rect_min.x = rect_min.x - pad;
    rect_min.y = rect_min.y - pad;

    rect_min.width = rect_min.width + 2*pad;
    rect_min.height = rect_min.height + 2*pad;

    Mat result = original.submat(rect_min);     
    Highgui.imwrite("result.png", result);

EDIT: Java code added!

Result

enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top