Permalink
Browse files

updated extract digits. Can work together with ocr now

  • Loading branch information...
Jennifer Guo
Jennifer Guo committed Jan 14, 2014
1 parent f342279 commit 662f8975034adf349b3eea0347e0c4eae8d822cc
Showing with 167 additions and 270 deletions.
  1. +167 −95 code/extract_digits/extractdigits.m
  2. +0 −175 code/extract_digits/extractdigits_new.m
@@ -1,110 +1,182 @@
-function [ output_struct ] = extractdigits( sudoku_image )
+function [ output_struct ] = extractdigits_new( sudoku_image )
%Takes a clean sudoku image and extract the digit portion
+% input sudoku_image should be a binary image!
% The output is a struct with the digit image vector and the
% location vector
-%Turn image into gray scale
-%gray_image = rgb2gray(sudoku_image);
-
-%Set the threshold level
-%level = graythresh(gray_image);
-
-%Convert whole image matrix to binary
-%binary_image = im2bw(gray_image, level);
-
-binary_image = sudoku_image;
-
-%Determine the window size
-[height, width] = size(binary_image);
-
-
-window_height = floor(height/9);
-window_width = floor(width/9);
-
-digit_images = {};
-digit_location = [];
-
-disp(window_height);
-disp(height);
-disp(window_width);
-disp(width);
-
-location = 1;
-count = 0;
-for grid_h=1:window_height:(height-window_height+1)
- for grid_w=1:window_width:(width-window_width+1)
- pixel_sum = 0;
-
- window = imcrop(binary_image, ...
- [grid_w, grid_h, window_width, window_height]);
-
- % determine inner rectangle
- stat = regionprops(window,'boundingbox');
- maxarea = 0;
- maxsquare = 0;
- for cnt = 1 : numel(stat)
- bb = stat(cnt).BoundingBox;
- area = bb(3) * bb(4);
- if area > maxarea
- maxarea = area;
- maxsquare = bb;
+ binary_image = sudoku_image;
+
+ %Determine the window size
+ [height, width] = size(binary_image);
+
+ window_height = floor(height/9);
+ window_width = floor(width/9);
+
+ digit_images = {};
+ digit_location = [];
+
+% imshow(sudoku_image);
+% hold on;
+
+ location = 1; % value from 1~81 to mark which square in sudoku box
+ index = 1; % value from 1 ~ #of squares with digits.
+ for grid_h=1:window_height:(height-window_height+1)
+ for grid_w=1:window_width:(width-window_width+1)
+
+ window = imcrop(binary_image, ...
+ [grid_w, grid_h, window_width, window_height]);
+
+ % determine rectangle
+ rect = get_rectangle(window);
+ cropped_img = imcrop(window, rect);
+
+ % Testing: draw rectangles in original image
+ r1 = [grid_w + rect(1,1)-1, grid_h + rect(1,2)-1, ...
+ rect(1,3), rect(1,4)];
+ %rectangle('position', r1, 'edgecolor', 'r', 'linewidth', 2);
+
+ % determine shrinked rectangle
+ shrinked_rect = shrink_rectangle(cropped_img);
+ cropped_img = imcrop(cropped_img, shrinked_rect); % crop image down again
+
+ if (contains_digit(cropped_img))
+ digit_location = [digit_location, location];
+ digit_images{1,index} = cropped_img;
+ index = index + 1;
+
+ % Testing: draw shrinked rectangle in original image
+ r2 = [r1(1,1) + shrinked_rect(1,1) - 1, r1(1,2) + shrinked_rect(1,2) - 1, ...
+ shrinked_rect(1,3), shrinked_rect(1,4)];
+ %rectangle('position', r2, 'edgecolor', 'g', 'linewidth', 2);
end
+
+ location = location + 1;
end
- %rectangle('position',maxsquare,'edgecolor','r','linewidth',2);
- inner_rectangle = imcrop(window, maxsquare);
- [inner_h, inner_w] = size(inner_rectangle);
-
- center_h = floor(inner_h / 2);
- center_w = floor(inner_w / 2);
-
- allblack_sum = 0;
- %Go over the window and calculate the number of black pixels
- for window_h=1:1:inner_h
- for window_w=1:1:inner_w
- dist_h = abs(window_h - center_h);
- dist_w = abs(window_w - center_w);
- dist = sqrt(dist_h * dist_h + dist_w * dist_w);
- if (dist == 0)
- dist = 1;
- end
- if (dist > inner_h / 6)
- allblack_sum = allblack_sum + 1/dist;
- end
- if(inner_rectangle(window_h, window_w) == 0)
- if (dist > inner_h /6)
- pixel_sum = pixel_sum + 1/dist;
- else
- pixel_sum = pixel_sum + 1;
- end
- end
- end
+ end
+
+ %Construct the struct for return
+ output_struct.digit_vector = digit_images;
+ output_struct.location_vector = digit_location
+
+end
+
+function [output_rectangle] = get_rectangle(window)
+% determines the inner rectangle of the current window. Used to remove the
+% borders of the grid in a first step. (afterwards we run
+% shrink_inner_rectangle to improve the result)
+% window: pass in the image of the window that we're iterating over
+% output_rectangle: outputs a rectangle [x y w h] as output that can be
+% used for imcrop then. Positions are relative to input "window"
+ stat = regionprops(window,'boundingbox');
+ maxarea = 0;
+ maxsquare = 0;
+ for cnt = 1 : numel(stat)
+ bb = stat(cnt).BoundingBox;
+ area = bb(3) * bb(4);
+
+ if (area > maxarea && area < (size(window,1) * size(window,2)))
+ maxarea = area;
+ maxsquare = bb;
end
- %If the total amount of black pixel exceeds a certain portion, then
- %count that window as containing digit
- if (location == 8 || location == 9)
- imshow(inner_rectangle);
- disp(pixel_sum);
- disp(allblack_sum);
+ end
+ output_rectangle = maxsquare;
+end
+
+function [output_rectangle] = shrink_rectangle(img)
+% the inner rectangle as determined by regionprops might still contain some
+% black pixels at the border. Use this function to shrink it to remove
+% those black pixels.
+% We look at the middle 1/3 strip of each side and shrink it until that
+% strip has only white pixels
+% img: the inner_rectangle as input
+% output_rectangle: return a rectangle [x y w h] as output, that can be
+% used for imcrop then. Positions are relative to input "img"
+
+ [h, w] = size(img);
+ v_length = floor(h/3); % vertical length
+ h_length = floor(w/3); % horizontal length
+
+ corners = zeros(2, 4); % saves the result coordinates of the 4 corners
+
+ % moving top edge down
+ y_pos = 1;
+ while (1)
+ hline = img(y_pos, h_length:2*h_length-1);
+ if (sum(hline) == h_length) % all white
+ break;
end
- if(pixel_sum > ((allblack_sum)/10))
- count = count + 1;
- %imshow(inner_rectangle,'Border', 'tight');
- digit_images{1,count} = inner_rectangle;
- %digit_images = [digit_images, [digit_image]];
- digit_location = [digit_location, location];
+ y_pos = y_pos + 1;
+ end
+ corners(2, 1:2) = y_pos;
+
+ % moving bottom edge up;
+ y_pos = h;
+ while (1)
+ hline = img(y_pos, h_length:2*h_length-1);
+ if (sum(hline) == h_length) % all white
+ break;
end
- %Keep track of digit location
- location = location + 1;
+ y_pos = y_pos - 1;
end
-end
-disp(location);
-%Construct the struct for return
-value1 = digit_images;
-field2 = 'location_vector'; value2 = digit_location;
+ corners(2, 3:4) = y_pos;
-output_struct = struct(field2, value2);
-output_struct.digit_vector = value1;
+ % moving left edge right
+ x_pos = 1;
+ while (1)
+ vline = img(v_length:2*v_length-1, x_pos);
+ if (sum(vline) == v_length) % all white
+ break;
+ end
+ x_pos = x_pos + 1;
+ end
+ corners(1, 1) = x_pos;
+ corners(1, 3) = x_pos;
+
+ % moving right edge left
+ x_pos = w;
+ while (1)
+ vline = img(v_length:2*v_length-1, x_pos);
+ if (sum(vline) == v_length) % all white
+ break;
+ end
+ x_pos = x_pos - 1;
+ end
+ corners(1, 2) = x_pos;
+ corners(1, 4) = x_pos;
+
+ output_rectangle = [corners(1,1), corners(2,1), corners(1,2)-corners(1,1), corners(2,3)-corners(2,1)];
end
+function [ret] = contains_digit (square)
+% determines if the square which we cropped out contains a digit
+% square: pass in the cropped down image. Has to be a bw image.
+% ret: return value either true (1) or false (0)
+
+ if (islogical(square) == 0)
+ error('input image is not a bw image!');
+ end
+ THRESHOLD_RATIO = 0.1;
+ [h, w] = size(square);
+
+ square = ~square; % let black pixels have value 1
+
+ % create a mask by dividing square into 9 regions and have the center
+ % region valued at 3 and the remaining at 1.
+ % this way we're weighing the center of the square more
+ % 1 1 1
+ % 1 3 1
+ % 1 1 1
+ mask = ones(h, w);
+ mask(floor(h/3)+1:floor(h/3*2), floor(w/3)+1:floor(w/3*2)) = 3;
+
+ allblack = sum(sum(mask));
+ black_pixels = sum(sum(square .* mask));
+
+ if (black_pixels / allblack > THRESHOLD_RATIO)
+ ret = true;
+ else
+ ret = false;
+ end
+end
Oops, something went wrong.

0 comments on commit 662f897

Please sign in to comment.