Extracting horizontal and vertical lines using morphology

Use morphology transformations for extracting horizontal and vertical lines sample code

Sources:

Contents

Music Sheet image

Load the source image

src = imread(fullfile(mexopencv.root(),'test','notes.png'));
imshow(src), title('source')

Transform source image to gray if it is not

if size(src,3) == 3
    gray = cv.cvtColor(src, 'RGB2GRAY');
else
    gray = src;
end

Transform grayscale image to binary by applying adaptiveThreshold on the bitwise_not of gray

assert(isinteger(gray), 'Must be integer type for BITCMP to work');
bw = cv.adaptiveThreshold(bitcmp(gray), 'MaxValue',255, ...
    'Method','Mean', 'Type','Binary', 'BlockSize',15, 'C',-2);
imshow(bw), title('binray')

Create the images that will use to extract the horizontal and vertical lines

horizontal = bw;
vertical = bw;

Horizontal Lines

% Specify size on horizontal axis
horizontalsize = fix(size(horizontal,2) / 30);

% Create structure element for extracting horizontal lines through morphology
% operations
horizontalStructure = cv.getStructuringElement(...
    'Shape','Rect', 'KSize',[horizontalsize,1]);

% Apply morphology operations
horizontal = cv.erode(horizontal, 'Element',horizontalStructure);
horizontal = cv.dilate(horizontal, 'Element',horizontalStructure);

% Show extracted horizontal lines
imshow(horizontal), title('horizontal')

Vertical Lines

% Specify size on vertical axis
verticalsize = fix(size(horizontal,1) / 30);

% Create structure element for extracting vertical lines through morphology
% operations
verticalStructure = cv.getStructuringElement(...
    'Shape','Rect', 'KSize',[1,verticalsize]);

% Apply morphology operations
vertical = cv.erode(vertical, 'Element',verticalStructure);
vertical = cv.dilate(vertical, 'Element',verticalStructure);

% Show extracted vertical lines
imshow(vertical), title('vertical')

Inverse vertical image

vertical = bitcmp(vertical);
%imshow(vertical), title('vertical_bit', 'Interpreter','none')

Smooth

Extract edges and smooth image according to the logic:

  1. extract edges
  2. dilate(edges)
  3. src.copyTo(smooth)
  4. blur smooth img
  5. smooth.copyTo(src, edges)
% step 1
edges = cv.adaptiveThreshold(vertical, 'MaxValue',255, ...
    'Method','Mean', 'Type','Binary', 'BlockSize',3, 'C',-2);

% step 2
kernel = ones(2,2,'uint8');
edges = cv.dilate(edges, 'Element',kernel);

% step 3
smooth = vertical;

% step 4
smooth = cv.blur(smooth, 'KSize',[2 2]);

% step 5
vertical(edges~=0) = smooth(edges~=0);

Show final result

imshow(vertical), title('smooth')