Anthony
Anthony

Reputation: 35998

Converting C++ OpenCV to Python

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?

Upvotes: 1

Views: 1251

Answers (1)

Nejc
Nejc

Reputation: 937

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'

Upvotes: 1

Related Questions