ofImage - mirror & rotate functionality

Hello,

I have modified the ofImage class to add mirror (horizontal & vertical) and rotate functionality.

Here is new code to add!

ofImage.h
after:

  
  
		void 				resize(int newWidth, int newHeight);  
  

add:

  
  
		void				mirror(bool horizontal, bool vertical);  
		void				rotate(float angle);  
  

after:

  
  
		void				resizePixels(ofPixels &pix, int newWidth, int newHeight);  
  

add:

  
  
		void				flipPixels(ofPixels &pix, bool horizontal, bool vertical);  
		void				rotatePixels(ofPixels &pix, float angle);  
  

ofImage.cpp
after:

  
  
//------------------------------------  
void ofImage::resize(int newWidth, int newHeight){  
	resizePixels(myPixels, newWidth, newHeight);  
	  
	tex.clear();  
	if (bUseTexture == true){  
		tex.allocate(myPixels.width, myPixels.height, myPixels.glDataType);	  
	}  
	  
	update();  
}  
  

add:

  
  
//------------------------------------  
void ofImage::mirror(bool horizontal, bool vertical){  
	flipPixels(myPixels, horizontal, vertical);  
	  
	update();  
}  
  
//------------------------------------  
void ofImage::rotate(float angle){  
	rotatePixels(myPixels, angle);  
	  
	tex.clear();  
	if (bUseTexture == true){  
		tex.allocate(myPixels.width, myPixels.height, myPixels.glDataType);	  
	}  
	  
	update();  
}  
  

after:

  
  
//----------------------------------------------------  
void ofImage::resizePixels(ofPixels &pix, int newWidth, int newHeight){  
	   
	FIBITMAP * bmp					= getBmpFromPixels(pix);  
	FIBITMAP * convertedBmp			= NULL;  
	  
	convertedBmp = FreeImage_Rescale(bmp, newWidth, newHeight, FILTER_BICUBIC);  
	putBmpIntoPixels(convertedBmp, pix);  
	  
	#ifdef TARGET_LITTLE_ENDIAN  
//		if (pix.bytesPerPixel != 1) swapRgb(pix); /** disabled to fix channel-marring bug (as per: [http://forum.openframeworks.cc/t/ofimage-resize-bug-in-00573-xcode-fat-ycam/1242/0](http://forum.openframeworks.cc/t/ofimage-resize-bug-in-00573-xcode-fat-ycam/1242/0)  

add:

  
  
//----------------------------------------------------  
void ofImage::flipPixels(ofPixels &pix, bool horizontal, bool vertical){  
	if(!horizontal && !vertical)  
		return;  
	  
	FIBITMAP * bmp					= getBmpFromPixels(pix);  
	bool horSuccess = false, vertSuccess = false;  
	  
	if(horizontal)  
		horSuccess = FreeImage_FlipHorizontal(bmp);  
	if(vertical)  
		vertSuccess = FreeImage_FlipVertical(bmp);  
  
	if(horSuccess || vertSuccess)  
		putBmpIntoPixels(bmp, pix);  
	  
	if (bmp != NULL)				FreeImage_Unload(bmp);  
}  
  
//----------------------------------------------------  
void ofImage::rotatePixels(ofPixels &pix, float angle){  
	if(angle == 0.0)  
		return;  
	  
	FIBITMAP * bmp					= getBmpFromPixels(pix);  
	FIBITMAP * convertedBmp			= NULL;  
	  
	convertedBmp = FreeImage_RotateClassic(bmp, angle);  
	putBmpIntoPixels(convertedBmp, pix);  
	  
	if (bmp != NULL)				FreeImage_Unload(bmp);  
	if (convertedBmp != NULL)		FreeImage_Unload(convertedBmp);  
}  
  

Hope this is helpful to someone out there!

Also, if anyone has any tips to make it better, I’d love to hear it!

Cheers!

thx! I am no c++ professional at all and your code taught me something new again :)= ‘it’s not a bug, it’s a feature!!!’

Thanks a lot !

I am a beginer of OF. I have tried the functions both of you two provided, if i rotate the image with an angle which is not a multiple of 90, the result image will have a black rectangle background. when i tried to solve this problem, i found the pixel of ofImage don’t support alpha channel , right? so, Is there any way to make the image background transparent??

It would be very nice if someone could help me, cause i’m suffering from this problem. Expecting your reply…

If you set your ofImage type to OF_IMAGE_COLOR_ALPHA you will be able to use alpha transparency. If you do that, then after your rotate, you could inspect the pixels and set black ones to be transparent.

  
myImage.setImageType(OF_IMAGE_COLOR_ALPHA);  

Obviously it’s not ideal to set all the black pixels because you might have some in your actual image. But there is definitely a relationship between the width, height, angle of rotation; and the black background areas. I don’t think it should be too hard to figure it out, and fill only those pixels. If I get some free time later on, I will look into this… hopefully someone beats me to it though!

basara, are you are just trying to rotate an image, or do you need to alter the pixels of the image?

if it’s simply to rotate, you could always:

  
  
ofPushMatrix();  
ofTranslate(100,100,0);  
ofRotateZ(30);  
// draw the image  
ofPopMatrix();  
  

take care!
zach

Thank plong0 and zach :?

I just want to rotate some images show on the screen.

I haven’t tried plong0’s method, yes, we can calculate the postion of backgroud pixels, but it needs to add more messy codes to do it. So, maybe sometime later i will have a try. :slight_smile:

Zach’s method can make image looks well after rotation, but it causes annother problem. The ‘ofRotateZ()’ changes the whole coordinate system. If I want to use the mouse to drag the image, firstly I need to make a transform between the mouse coordinate and the image coordinate?And in my project, the calculation of coordinates appear in many places, so it may be complicated to transform correctly all the time… I think this problem could be sovled, and I am working on it. But still , any suggustions?

Once again, very grateful for your work!

Hi,

I would really happy if there is overloaded draw() function like:

  
  
  
ofImage img;  
  
img.draw(float xPos, float yPos, int iximgOffset, int iyimgOffset, int iWidth, int iHeight);  
  
  

Internally, it just modify raw image pointer with something like:

  
  
  
ptrRaw = (imgWidth*COLOR_DEPTH*iyimgOffset) + (iximgOffset*COLOR_DEPTH)  
  
  

then iterate to copy to another temporary storage with iWidth and iHeight of course they should be checked with real image width and height.

:oops:

[quote author=“zach”]basara, are you are just trying to rotate an image, or do you need to alter the pixels of the image?

if it’s simply to rotate, you could always:

  
  
ofPushMatrix();  
ofTranslate(100,100,0);  
ofRotateZ(30);  
// draw the image  
ofPopMatrix();  
  

take care!
zach[/quote]

using matrix rotation, I found that I had to translate to the image center, rotate, then translate back to -'ve image center…
something like…

  
  
	ofPushMatrix();  
	ofTranslate(x+w/2.0, y+h/2.0, 0);  
	ofRotateZ(this->rotation);  
	ofTranslate((x+w/2.0)*-1.0, (y+h/2.0)*-1.0, 0);  
	myImage.draw(x, y);  
	ofPopMatrix();  
  

An easier way is using the new setAnchorPercent paramater of ofImage

Say you wanted an image to be drawn with the center at 100, 100 and rotate around this point:

  
ofPushMatrix();  
ofTranslate(100, 100, 0);  
ofRotate(45);   
img.setAnchorPercent(0.5, 0.5);  
img.draw(0, 0);   
ofPopMatrix();  
  

SetAnchorPercent sets the drawing point of the image.

Normally it is the top left corner but by doing 0.5, 0.5, you are setting the drawing point to be the center of the image.

true… but I was actually using the matrix rotation to rotate a group of elements that are meant to be oriented together. (ie. start rotation matrix, draw rectangle, draw image, draw another rectangle, etc).

I am about to start looking into how to kill the black pixels and also resize the image when it gets rotated (so it doesn’t crop off corners and what not). I’ll post any new code solutions.

Whoops, I should have checked the forum first! I implemented a very specific rotation that I needed just now (90 degrees counter clockwise):

  
  
class ofImage {  
...  
ofImage temp;  
void rotate() {  
	int w = (int) img.getWidth();  
	int h = (int) img.getHeight();  
	temp.allocate(h, w, img.type);  
	unsigned char* srcPixels = img.getPixels();  
	unsigned char* destPixels = temp.getPixels();  
	int destPosition = 0, srcPosition = 0;  
	for(int y = 0; y < h; y++) {  
		for(int x = 0; x < w; x++) {  
			destPosition = (x * h + y) * 3;  
			srcPosition = (y * w + x) * 3;  
			destPixels[destPosition + 0] = srcPixels[srcPosition + 0];  
			destPixels[destPosition + 1] = srcPixels[srcPosition + 1];  
			destPixels[destPosition + 2] = srcPixels[srcPosition + 2];  
		}  
	}  
	img.allocate(h, w, img.type);  
	img.setFromPixels(destPixels, h, w, img.type);  
}  
...  
}  
  

I need to “actually” rotate, as I’m saving the image(s) to disk – it’d be great to have these mirroring and rotation functions in the core.

These mods are now packaged into an ofxImage addon.

ofxImage-Topic

easy way is use an image app to-rotate-images for you, if it is the case, i suggest one rotate selected images counterclockwise or with a customized rotation angle.