Jason
Jason

Reputation: 11363

Python OpenCV - File rotating, but color values are overwritten

I'm experimenting with OpenCV and Python's bindings. This code is intended to rotate an image with a command line argument value. However, it is saving as an exact copy of the input image, with no rotation whatsoever.

This code is adapted from this answer

import cv2 as cv

def rotateImage(self, image, angle):
    print "Rotating image to angle: %s" % (angle)

    print type(image) #image is numpy.ndarray
    print type(angle) #angle is float

    center = tuple(np.array(image.shape[0:2])/2)
    matrix = cv.getRotationMatrix2D(center, angle, 1.0)
    rotate = cv.warpAffine(image, matrix, image.shape[0:2], flags=cv.INTER_LINEAR)

    fileList = self.filename.split(".")
    newFile = fileList[0] + "_rotate_%s." % (int(angle)) + fileList[1]

    print "Saving to %s" % (newFile)
    cv.imwrite(newFile, rotate)

My issue is the image saved after rotation isn't the one being input.

Input image: enter image description here

Output: enter image description here

Given these input and output, how can I alter the image dimensions to allow for 30 and 45 degree rotations?

Upvotes: 1

Views: 875

Answers (1)

John1024
John1024

Reputation: 113814

The issue is that, after rotation, your image extends out past the edges of the original shape. The solution is to extend the original image and then rotate. That way, important parts are not cut-off:

import cv2 as cv
import numpy as np

def extend(image):
    nrow, ncol, ncolor = image.shape
    n = int((nrow**2 + ncol**2)**.5//2 + 1)
    new = np.zeros((2*n, 2*n, ncolor))
    a = nrow//2
    b = ncol//2
    new[n-a:n-a+nrow, n-b:n-b+ncol, :] = image
    return new

def rotateImage(fname, angle):
    print "Rotating image to angle: %s" % (angle)

    image = cv.imread(fname, -1)
    print type(image) #image is numpy.ndarray
    print type(angle) #angle is float
    image = extend(image)

    center = tuple(np.array(image.shape[0:2])/2)
    matrix = cv.getRotationMatrix2D(center, angle, 1.0)
    rotate = cv.warpAffine(image, matrix, image.shape[0:2], flags=cv.INTER_LINEAR)

    fileList = fname.split(".")
    newFile = fileList[0] + "_rotate_%s." % (int(angle)) + fileList[1]

    print "Saving to %s" % (newFile)
    cv.imwrite(newFile, rotate)

The extend function creates a larger array (size based on the diagonal of the original image) and puts the original image in the center. I created the larger image with np.zeros which means the image that extend returns has a large black border. This extension needs to be done before the image is rotated.

Your image, after 45 degree rotation, looks like:

enter image description here

Upvotes: 3

Related Questions