Fastest way to block copy pixels?

what is the fastest way to block copy pixels in an oftexture or ofpixels object?

I want to copy a complete image and move across the x axis a few pixels as a block.
at present i’m iterating through every pixel with getcolor and setcolor which is hugely inefficient.

the method pixelsSource.pasteInto(pixelsTarget, x, y);
is not working for me -
can anyone advise me on a better/ faster way to move around large pixel blocks?

funny how working out how to ask the question helps find the answer…

probably horribly brute force but using loadscreen with a repeating offset increases speed nearly 10x

videoTexture.loadScreenData(camWidth/2, 0, videoPixels.getWidth(), videoPixels.getHeight());

then

    videoTexture.draw(camWidth/2+1, 0); 

there must be a better way - suggestions?

d

Hi. & bump. Also interested. On the gpu side appears that glTexSubImage2D, or glBlitFramebuffer, are the way to go.

I’ve been having lots of improvement on the cpu side by defining pixels in images as 32bit words and lovely bit shifting to achieve lower bandwith & faster speeds with byte precision rgba.

1 Like

Hi you can either simply load your image into a shader and in it use some specific logic for “copying” the pixels. You can use an ofFbo to render the shader so you then can use re use on the next drawing cycle.
If you simply want to draw it you can draw the texture several times with different subsections.
you can use ofImage's following function

    /// \param x X position to draw cropped image at.
    /// \param y Y position to draw cropped image at.
    /// \param w Width of subsection to draw.
    /// \param h Height of subsection to draw.
    /// \param sx X position in image to begin cropping from.
    /// \param sy Y position in image to begin cropping from.
    void drawSubsection(float x, float y, float w, float h, float sx, float sy) const;

Last thing you can do is simply access the array of data and copy (even using a memcpy, which can be a bit scary if you dont know exactly whats going on)

ofImage img;
img.load(....);

//define an area to copy by a rectangle in the number below!
int x ;
int y;
int w; 
int h;

ofImage imgBlock;
img.getPixels().cropTo(imgBlock.getPixels(),x,y, w, h); 
imgBlock.update();

//or instead you can go much nastier and do a memcpy, but I am a bit tired now to think on the right indices to use. :stuck_out_tongue: hope this is helpful

1 Like

Would enjoy too see where this goes, other alternatives :wink: see bitshifting performance here


ofImage screenbuffer;
	bool usetexture = true;
	float elapsed;
	float elapsedbit;

	void setup(){
		// screenbuffer.allocate(w,h,OF_IMAGE_COLOR_ALPHA);
		screenbuffer.allocate(w,h,OF_IMAGE_COLOR);
		screenbuffer.setUseTexture(true);
	}
	void keyPressed(int k){ usetexture^=true; screenbuffer.setUseTexture(usetexture);screenbuffer.allocate(w,h,OF_IMAGE_COLOR);}

	void update(){

		ofPixelsRef pixels = screenbuffer.getPixels();
		float nowimgbegin = ofGetElapsedTimef();
		float nowimgend = ofGetElapsedTimef();

		// see setFromPixels ofPixelsRef uses memcpy
		int ntests = numuploadsframe; while(ntests--){

			int i=0; while(i++<wh){
				// pixels.setColor(x,y,
				pixels.setColor(i,
					// ofColor(
					// 	ofRandom(255),ofRandom(255),ofRandom(255)
					// );
					ofColor(
						rand()%(255),rand()%(255),rand()%(255)
					));
			}
		}


		nowimgend = ofGetElapsedTimef();
		elapsed = nowimgend - nowimgbegin;


		nowimgbegin = ofGetElapsedTimef();

		ntests = numuploadsframe; while(ntests--){

			int i=0; while(i++<wh){
				// is this not working??? pixels.setColor(index seems broken)
				// pixels.setColor(i,
				int x = i%w; int y=i/w;
				pix = rand();
				pixels.setColor(x,y,
					ofColor((pix&255), (pix>>8)&255,(pix>>16)&255
					// ofColor((pix), (pix>>8),(pix>>16)
					));
			}
		}

		nowimgend = ofGetElapsedTimef();
		elapsedbit = nowimgend - nowimgbegin;


		screenbuffer.update();
	}

thanks everyone - been busy with other things - will try out the suggestions next week and let you know what i find.

D

I hope it’s ok to tag on this questions.

I am less interested in how to copy a block of pixels. But rather I have a list of 32000 pixel locations that need to be sampled for their color and then drawn drawn in an other known location.
Should I pass my FBO to a shader, have a 32k position look-up-table stored in the shader, which then samples location A and drawn this color in location B.
Does that make sense?

Hi @stephanschulz
I would say that it makes a lot of sense doing it on a shader. If it is possible it will probably be a lot faster than on the CPU. You can either use a texture to pass the look up table to the shader or a texture buffer ( look at the example in examples/gl/textureBufferInstancedExample).
Let me know how it goes.
best

@roymacdonald thanks for this.

I looked at it and it seems to allow me to draw an object at any location inside the shader canvas, with vector<glm::mat4> matrices specifying where to draw the shape.

But in my case I have a large ofFbo with ever changing graphics. But I only need to sample 32k locations in that ofFbo and the color in those locations need to be drawn somewhere else.

I thought the 09_gaussianBlurFilter example might work, but it performs a transformation on specific colors not pixels.

For example this modified shaderBlurX.frag shader translates the whole texture by n pixels.

void main()
{
    vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
    color +=  texture(tex0, texCoordVarying + vec2(blurAmnt,blurAmnt));
    outputColor = color;
}

Ideally I would upload my large ofFbo texture to the shader + a 32k large ofVec2f() array and use this array to move only those pixels.

I will see if I can combine the .glsl example with the .frag example somehow.

Hi @stephanschulz
I see.
I pointed out to that example as that is an easy an efficient way to pass data to a shader.
so, instead of passing matrices you can pass the sampling locations(which can be static or dynamically updated), and then draw each of these elsewhere as you noted. So, you still use the instanced drawing, but instead of drawing boxes flying around you can draw rectangles. The position of these rectangles you can also set it in the shader, on the vertex though, based on the instanceID and a uniform specifiying the size of each rectangle and the number of these to be drawn per row.