Rotating or Resizing an Image in OpenCV

The page will show you how to do some common image transformations in OpenCV, such as rotating an image, cropping an image or resizing an image without changing its aspect ratio.

Rotating an Image in OpenCV

The function below will rotate an image using cvGetQuadrangleSubPix(), which is supposed to be the faster way of rotating images in OpenCV compared to cvWarpAffine().

// Rotate the image clockwise (or counter-clockwise if negative).
// Remember to free the returned image.
IplImage *rotateImage(const IplImage *src, float angleDegrees)
{
	// Create a map_matrix, where the left 2x2 matrix
	// is the transform and the right 2x1 is the dimensions.
	float m[6];
	CvMat M = cvMat(2, 3, CV_32F, m);
	int w = src->width;
	int h = src->height;
	float angleRadians = angleDegrees * ((float)CV_PI / 180.0f);
	m[0] = (float)( cos(angleRadians) );
	m[1] = (float)( sin(angleRadians) );
	m[3] = -m[1];
	m[4] = m[0];
	m[2] = w*0.5f;  
	m[5] = h*0.5f;  

	// Make a spare image for the result
	CvSize sizeRotated;
	sizeRotated.width = cvRound(w);
	sizeRotated.height = cvRound(h);

	// Rotate
	IplImage *imageRotated = cvCreateImage( sizeRotated,
		src->depth, src->nChannels );

	// Transform the image
	cvGetQuadrangleSubPix( src, imageRotated, &M;);

	return imageRotated;
}

Cropping or ‘Cutting’ an Image in OpenCV

You can crop images to a rectangular region using cvSetImageROI() with cvCopy(). Note that this assumes the input image does not already have a ROI set.

// Returns a new image that is a cropped version (rectangular cut-out)
// of the original image.
IplImage* cropImage(const IplImage *img, const CvRect region)
{
	IplImage *imageCropped;
	CvSize size;

	if (img->width <= 0 || img->height <= 0
		|| region.width <= 0 || region.height <= 0) {
		//cerr << "ERROR in cropImage(): invalid dimensions." << endl;
		exit(1);
	}

	if (img->depth != IPL_DEPTH_8U) {
		//cerr << "ERROR in cropImage(): image depth is not 8." << endl;
		exit(1);
	}

	// Set the desired region of interest.
	cvSetImageROI((IplImage*)img, region);
	// Copy region of interest into a new iplImage and return it.
	size.width = region.width;
	size.height = region.height;
	imageCropped = cvCreateImage(size, IPL_DEPTH_8U, img->nChannels);
	cvCopy(img, imageCropped);	// Copy just the region.

	return imageCropped;
}

Resizing or ‘Zooming’ an Image in OpenCV

OpenCV has the “cvResize()” function to resize images easily. The problem with resizing images using cvResize() is that the aspect ratio or shape of the image will change. For example, if you try to enlarge a photo of a person so that it will cover the whole screen or window, then the person will probably look very fat or tall, because cvResize will change their shape! Many graphical software and views have a feature where you can ask to resize an image but to keep the aspect ratio the same.

Resizing while keeping the Aspect Ratio the same

The function “resizeImage()” shown below will resize an image nicely and can keep the aspect ratio the same (if desired). It will use “CV_INTER_AREA” to make an image smaller or “CV_INTER_LINEAR” to make an image larger, since they work well for those purposes. It will also allocate the memory for the image by itself, so unlike “cvResize()”, you shouldn’t call “cvCreateImage()” for an image before storing “resizeImage()” into that variable.

To make sure the aspect ratio stays the same, rotation may use the above crop function to remove the top and bottom edges and then actually call itself again with different parameters to resize the middle of the image, using a constant aspect ratio.

// Creates a new image copy that is of a desired size. The aspect ratio will
// be kept constant if 'keepAspectRatio' is true, by cropping undesired parts
// so that only pixels of the original image are shown, instead of adding
// extra blank space.
// Remember to free the new image later.
IplImage* resizeImage(const IplImage *origImg, int newWidth,
	int newHeight, bool keepAspectRatio)
{
	IplImage *outImg = 0;
	int origWidth;
	int origHeight;
	if (origImg) {
		origWidth = origImg->width;
		origHeight = origImg->height;
	}
	if (newWidth <= 0 || newHeight <= 0 || origImg == 0
		|| origWidth <= 0 || origHeight <= 0) {
		//cerr << "ERROR: Bad desired image size of " << newWidth
		//	<< "x" << newHeight << " in resizeImage().\n";
		exit(1);
	}

	if (keepAspectRatio) {
		// Resize the image without changing its aspect ratio,
		// by cropping off the edges and enlarging the middle section.
		CvRect r;
		// input aspect ratio
		float origAspect = (origWidth / (float)origHeight);
		// output aspect ratio
		float newAspect = (newWidth / (float)newHeight);
		// crop width to be origHeight * newAspect
		if (origAspect > newAspect) {
			int tw = (origHeight * newWidth) / newHeight;
			r = cvRect((origWidth - tw)/2, 0, tw, origHeight);
		}
		else {	// crop height to be origWidth / newAspect
			int th = (origWidth * newHeight) / newWidth;
			r = cvRect(0, (origHeight - th)/2, origWidth, th);
		}
		IplImage *croppedImg = cropImage(origImg, r);

		// Call this function again, with the new aspect ratio image.
		// Will do a scaled image resize with the correct aspect ratio.
		outImg = resizeImage(croppedImg, newWidth, newHeight, false);
		cvReleaseImage( &croppedImg; );

	}
	else {

		// Scale the image to the new dimensions,
		// even if the aspect ratio will be changed.
		outImg = cvCreateImage(cvSize(newWidth, newHeight),
			origImg->depth, origImg->nChannels);
		if (newWidth > origImg->width && newHeight > origImg->height) {
			// Make the image larger
			cvResetImageROI((IplImage*)origImg);
			// CV_INTER_LINEAR: good at enlarging.
			// CV_INTER_CUBIC: good at enlarging.			
			cvResize(origImg, outImg, CV_INTER_LINEAR);
		}
		else {
			// Make the image smaller
			cvResetImageROI((IplImage*)origImg);
			// CV_INTER_AREA: good at shrinking (decimation) only.
			cvResize(origImg, outImg, CV_INTER_AREA);
		}

	}
	return outImg;
}

You can call this function from your code like this:

IplImage *imgIn = cvLoadImage("my_photo.jpg");

// Create a new image copy that is the correct size and aspect ratio.
IplImage *imgA = resizeImage(imgIn, 1024, 768, true);
// Create a new image copy with wrong aspect ratio, just like cvResize().
IplImage *imgB = resizeImage(imgIn, 1024, 768, false);

// Save the resized images.
cvSaveImage("imgA.jpg", imgA);
cvSaveImage("imgB.jpg", imgB);

// Free the images
cvReleaseImage(&imgIn;);
cvReleaseImage(&imgA;);
cvReleaseImage(&imgB;);

Leave a Reply

Your email address will not be published. Required fields are marked *