Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Following more or less the technique that I am applying here and here. I am getting the following results, which it seems to be what you want.

image description

image description

image description

I consider that the title of the song has always the same distance from the detected horizontal line, if this is not the case then some further modification most likely will be needed. I am not uploading any code since most of it is based on the two links that I have provided earlier. However, if you still want it just tell me and I will uploaded here.

Following more or less the technique that I am applying here and here. I am getting the following results, which it seems to be what you want.

image description

image description

image description

I consider that the title of the song has always the same distance from the detected horizontal line, if this is not the case then some further modification most likely will be needed. I am not uploading any code since most of it is based on the two links that I have provided earlier. However, if you still want it just tell me and I will uploaded here.


here you go:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat src = imread("sheet1.jpg");

    if(!src.data)
    {
        cerr << "Problem loading image!!!" << endl;
        return EXIT_FAILURE;
    }

//        imshow("src", src);

    // resizing for practical reasons, small screen here :-p
    Mat rsz;
    Size size(800, 900);
    resize(src, rsz, size);

    imshow("rsz", rsz);

    Mat gray;
    cvtColor(rsz, gray, CV_BGR2GRAY);

    // Apply adaptiveThreshold at the bitwise_not of gray, notice the ~ symbol
    Mat bw;
    adaptiveThreshold(~gray, bw, 255, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);

    // Dilate a bit in order to correct possible gaps
    Mat kernel = Mat::ones(2, 2, CV_8UC1);
    dilate(bw, bw, kernel);

    // Show binary image
    imshow("bin", bw);

    // Create the images that will use to extract the horizonta and vertical lines
    Mat horizontal = bw.clone();

    // Specify size on horizontal axis
    int scale = 10; // play with this variable in order to increase/decrease the amount of lines to be detected
    int horizontalsize = horizontal.cols / scale;

    // Create structure element for extracting horizontal lines through morphology operations
    Mat horizontalStructure = getStructuringElement(MORPH_RECT, Size(horizontalsize,1));

    // Apply morphology operations
    erode(horizontal, horizontal, horizontalStructure, Point(-1, -1));
    dilate(horizontal, horizontal, horizontalStructure, Point(-1, -1));

    // Show extracted horizontal lines
    imshow("horizontal", horizontal);


    // Create the images that will use to extract the horizonta and vertical lines
    Mat vertical = bw.clone();

    // Specify size on horizontal axis
    int verticalsize = vertical.cols / scale;

    // Create structure element for extracting horizontal lines through morphology operations
     Mat verticalStructure = getStructuringElement(MORPH_RECT, Size( 1,verticalsize));

    // Apply morphology operations
    erode(vertical, vertical, verticalStructure, Point(-1, -1));
    dilate(vertical, vertical, verticalStructure, Point(-1, -1));

    // Show extracted horizontal lines
    imshow("vertical", vertical);

    Mat joints = horizontal + vertical;
    imshow("joints", joints);

    // Find external contour
    vector<Vec4i> hierarchy;
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(horizontal, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    vector<vector<Point> > contours_poly( contours.size() );
    vector<Rect> boundRect( contours.size() );

    // Draw the contour as a solid blob filling also any convexity defect with the extracted hulls
    for (size_t i = 0; i < contours.size(); i++)
    {
//        cout << boundRect[i].tl() << endl;
//        cout << boundRect[i].br() << endl << endl;

//        cout << arcLength(cv::Mat(contours[i]), true) << endl;
        double length = arcLength(cv::Mat(contours[i]), true);

        // filter long and short lines
        if(length < 75 || length > 1500)
            continue;

        approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
        boundRect[i] = boundingRect( Mat(contours_poly[i]) );
//        if(length > 200)
//        {
//            boundRect[i] += Size(0, -40); // expanding rectangle by a certain amount
//            boundRect[i] -= Point(0, 3); // shifting rectangle by a certain offset
//        }else{
            boundRect[i] += Size(0, 30);
            boundRect[i] -= Point(0, -4);
//        }

        drawContours( rsz, contours, i, Scalar(0, 0, 255), CV_FILLED, 8, vector<Vec4i>(), 0, Point() );
        rectangle( rsz, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 1, 8, 0 );
    }

    cv::findContours(vertical, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    for (size_t i = 0; i < contours.size(); i++)
        drawContours( rsz, contours, i, Scalar(0, 0, 255), CV_FILLED, 8, vector<Vec4i>(), 0, Point() );

    imshow("src", rsz);

    /* Now you can do whatever post process you want
     * with the data within the rectangles. */

    waitKey(0);
    return 0;
}