1

I am trying to remove horizontal and vertical lines from my images that look like this: enter image description here

While googling I found a solution that I believe might work: Extract horizontal and vertical lines by using morphological operations, however, it is in C++.

I have tried converting the solution to Python, but I don't get the same results. In order to keep the image same, I've tried my python version on the same image used in that solution:

Below is my python version with relevant c++ version in the comments:

    img = cv2.imread(path)
    img=cv2.cvtColor(img,cv2.COLOR_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);
    th2 = cv2.adaptiveThreshold(img,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,15,-2)
    cv2.imwrite("th2.jpg", th2)

    #Mat horizontal = bw.clone();
    #Mat vertical = bw.clone();
    horizontal = th2
    vertical = th2

    #int horizontalsize = horizontal.cols / 30;
    rows,cols = horizontal.shape
    horizontalsize = cols / 30

    #// Create structure element for extracting horizontal lines through morphology operations
    #Mat horizontalStructure = getStructuringElement(MORPH_RECT, Size(horizontalsize,1));
    horizontalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (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);
    horizontal = cv2.erode(horizontal, horizontalStructure, (-1, -1))
    horizontal = cv2.dilate(horizontal, horizontalStructure, (-1, -1))
    cv2.imwrite("horizontal.jpg", horizontal)

    #// Specify size on vertical axis
    #int verticalsize = vertical.rows / 30;
    verticalsize = rows / 30

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

    #// Apply morphology operations
    #erode(vertical, vertical, verticalStructure, Point(-1, -1));
    #dilate(vertical, vertical, verticalStructure, Point(-1, -1));
    #// Show extracted vertical lines
    #imshow("vertical", vertical);

    vertical = cv2.erode(vertical, verticalStructure, (-1, -1))
    vertical = cv2.dilate(vertical, verticalStructure, (-1, -1))
    cv2.imwrite("vertical.jpg", vertical)

    #// Inverse vertical image
    #bitwise_not(vertical, vertical);
    #imshow("vertical_bit", vertical);

    vertical = cv2.bitwise_not(vertical)
    cv2.imwrite("vertical_bit.jpg", vertical)

    #// 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)


    #step1
    #Mat edges;
    #adaptiveThreshold(vertical, edges, 255, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, -2);
    #imshow("edges", edges);
    edges = cv2.adaptiveThreshold(vertical,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,3,-2)
    cv2.imwrite("edges.jpg", edges)

    #step2
    #Mat kernel = Mat::ones(2, 2, CV_8UC1);
    #dilate(edges, edges, kernel);
    #imshow("dilate", edges);
    kernel = np.ones((2, 2), dtype = "uint8")
    dilated = cv2.dilate(edges, kernel)
    cv2.imwrite("dialted.jpg", dilated)

    # step3
    #Mat smooth;
    #vertical.copyTo(smooth);
    smooth = vertical.copy()

    #step 4
    #blur(smooth, smooth, Size(2, 2));
    smooth = cv2.blur(smooth, (2,2))

    #step 5
    #smooth.copyTo(vertical, edges);
    (rows, cols) = np.where(edges != 0)
    vertical[rows, cols] = smooth[rows, cols]

    // Show final result
    #imshow("smooth", vertical);
    cv2.imwrite("smooth.jpg", vertical)

When I run this on enter image description here

I get back

enter image description here

which is not the result that the solution linked above gets.

I belive the problem might be in my conversion of this c++ line:

// 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);

to this python line

th2 = cv2.adaptiveThreshold(img,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,15,-2)

Question

How can I best convert the C++ code in the linked solution to Python?

3
  • That's the only line that is different... When you called the adaptive threshold method. Try actually inverting the input image. You can use the same operator as in C++. Use ~. Commented Feb 25, 2017 at 19:10
  • @rayryeng Thanks. This works well for the image mentioned in the solution, however, it doesn't work well for my image. I don't get good results at all. I was wondering if you could take a look? I've kept everything in a simple gist gist.github.com/anonymous/058999a32bde41aba5ccce754fd3cc05 Commented Feb 25, 2017 at 19:50
  • It was better to ask a separate question stackoverflow.com/questions/42461211/… Commented Feb 25, 2017 at 20:30

1 Answer 1

1

Looks like that you have the problem because of tilde operator that applies bitwise NOT operation to all pixels in the image. Look at this three lines of C++ code:

cv::Mat img = imread("smiley.png", IMREAD_GRAYSCALE);
imshow("Image0", img);
imshow("Image1", ~img); // tilde

These are the images you get:

enter image description here enter image description here

Quick solution: if you want to apply thresholding correctly then either

  • apply bitwise negation to the input array, or
  • use 'THRESH_BINARY_INV' instead of 'THRESH_BINARY'
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. This works well for the image mentioned in the solution, however, it doesn't work well for my image. I don't get good results at all. I was wondering if you could take a look? I've kept everything in a simple gist gist.github.com/anonymous/058999a32bde41aba5ccce754fd3cc05
It was better to ask a separate question stackoverflow.com/questions/42461211/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.