3

My Images;

enter image description here

enter image description here

enter image description here

enter image description here

Requirement:

enter image description here

I am not able to understand how axis is decided to make the image always horizontal.

Algorithm:

  • Read the image
  • Find external contour
  • Draw the contours
  • Use the external contour to detect minArearect (bounding box will not help for me)
  • get the rotation matrix and rotate the image
  • Extract the required patch from the rotated image

My code:

//read the image
img = imread("90.jpeg")
cv::Mat contourOutput = img.clone();

// detect external contour(images will have noise, although example images doesn't have)

std::vector<std::vector<cv::Point> > contours;
cv::findContours(contourOutput, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

int largest_area = 0;
int largest_contour_index = 0;
for (size_t i = 0; i < contours.size(); i++) {
    double area = contourArea(contours[i]);

// copy the largest contour index
    if (area > largest_area) {
        largest_area = area;
        largest_contour_index = i;
}
}
//draw contours
drawContours(img, contours, largest_contour_index, Scalar(255, 0, 0),
             2);
// detect minimum area rect to get the angle and centre
cv::RotatedRect box = cv::minAreaRect(cv::Mat(contours[largest_contour_index]));
// take the box angle
double angle = box.angle;
if (angle < -45) {
    box.angle += 90;
}

angle = box.angle;
// create rotation matrix
cv::Mat rot_mat = cv::getRotationMatrix2D(box.center, angle, 1);

// Apply the transformation
cv::Mat rotated;
cv::warpAffine(img, rotated, rot_mat, img.size(), cv::INTER_CUBIC);
cv::Size box_size = box.size;

if (box.angle < -45.)
    std::swap(box_size.width, box_size.height);
// get the cropped image
cv::Mat cropped;
cv::getRectSubPix(rotated, box_size, box.center, cropped);

// Display the image
namedWindow("image2", WINDOW_NORMAL);
imshow("image2", cropped);
waitKey(0);
nathancy
  • 42,661
  • 14
  • 115
  • 137
  • do you need the angle or the rotation center, or what is the problem? Have a look at my answer in: https://stackoverflow.com/questions/34237253/detect-centre-and-angle-of-rectangles-in-an-image-using-opencv/34285205#34285205 – Micka Dec 01 '19 at 12:02
  • I am getting the angle, but i'm not sure how to always make it 180 degrees(horizontal to x-axis) :( As my image angles keeps varying. I am a newbie in this and i'm stuck from 1 day! Please help –  Dec 01 '19 at 12:11
  • if the angle is 10 degrees, rotate the image and the box by 170 degrees. if it is 33.3, rotate it by 146.7, and so on – Micka Dec 01 '19 at 12:16
  • i made it work like that! but how do i infer when to swap box.width and box.height. Should i have to find the contour again and draw boundingrect to crop ? This relates to same question to make the minAreaRect horizontal –  Dec 01 '19 at 16:41

1 Answers1

0

The idea is to compute the rotated bounding box angle using minAreaRect then deskew the image with getRotationMatrix2D and warpAffine. One final step is to rotate by 90 degrees if we are working with a vertical image. Here's the results with before (left) and after (right) and the angle of rotation:

-39.999351501464844

38.52387619018555

1.6167902946472168

1.9749339818954468

I implemented it in Python but you can adapt the same approach into C++

Code

import cv2
import numpy as np

# Load image, grayscale, and Otsu's threshold
image = cv2.imread('4.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Compute rotated bounding box
coords = np.column_stack(np.where(thresh > 0))
angle = cv2.minAreaRect(coords)[-1]

# Determine rotation angle
if angle < -45:
    angle = -(90 + angle)
else:
    angle = -angle
print(angle)

# Rotate image to deskew
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

# Vertical image so rotate to horizontal
h, w, _ = rotated.shape
if h > w:
    rotated = cv2.rotate(rotated, cv2.ROTATE_90_CLOCKWISE)

cv2.imshow('rotated', rotated)
cv2.imwrite('rotated.png', rotated)
cv2.waitKey()
nathancy
  • 42,661
  • 14
  • 115
  • 137