Why rendering engines subdivide an image in small squares? - c++

Imagine that I have an image in memory that is represented by an array or an std::vector; for the sake of this example I'm also assuming that my image is like 400x300 pixels and I want to subdivide this structure in squares ( or tiles ) that are 64x64 pixels maximum.
The array that I'm considering is declared like this
int a[400*300];
and not like
int a[400][300];
It's 1 nice contiguous chunk of memory.
My point is that you always try to keep the data structure and the access to that data structure as much as linear as possible . Subdividing the image in squares involves jumping from 1 row to another or from 1 column to another depending on how the image is laid out in memory. I have no problem in computing the boundaries for the squares given a size and the dimensions of the image, but things get a little bit too complicated when expressing the iteration over this squares, without me seeing any real benefit in having this approach.
So why the solution about this kind of subdivision steps is so popular ? why not just render like 1 row at time or 1 column at time ?

Memory locality / cache coherency. Most image processing operations operate in 2D and for efficient memory access you want pixels that are close to each other in 2D to be close to each other in memory. Arranging the data in blocks like this means that 2 pixels that have the same x coordinate and adjacent y coordinates will on average have closer memory addresses than if you used a simple linear layout.
There are more complex ways of laying out the image that are often used for textures when rendered by GPUs which give even better memory locality on average.

Related

Pack pixels in 1bit/bw/binary image in boxes

I need an algorithm that, from a 1bit 2D image (a 2D matrix of mixed 1s and 0s) returns me rectangles (with the x,y coordinates of each corner) that packs the pixels that are equal to zero, using the least amount of boxes.
So for an image like
0000000
1111111
1111111
1111110
1111100
0000000
It would return something like
Rectangle 1 ((0,0),(0,1),(7,0),(7,1))
Rectangle 2 ((6,3),(7,3),(7,4),(6,4))
Rectangle 3 ((5,4),(7,4),(7,6),(5,6))
Rectangle 4 ((0,5),(0,6),(7,6),(7,5))
I feel this algorithm exists, but I am unable to Google it or name it.
I'm guessing you're looking to make a compression algorithm for your images. There isn't an algorithm that guarantees the minimum number of rectangles, as far as I'm aware.
The first thing that comes to mind is taking your pixel data as a 1D array and using run-length encoding to compress it. Images tend to have rather large groupings of similarly-colored pixels, so this should give you some data savings.
There are some things you can do on top of that to further increase the information density:
Like you suggested, start off with an image that is completely white and only store black pixels
If encoding time isn't an issue, run your encoding on both white and black pixels, then store whichever requires less data and use one bit to store whether the image should start with a black or a white background.
There are some algorithms that try to do this in two dimensions, but this seems to be quite a bit more complex. Here's one attempt I found on the topic:
https://pdfs.semanticscholar.org/d09a/62ea3472352bf7bbe873677cd81f348206cc.pdf
I found more interesting SO answers:
What algorithm can be used for packing rectangles of different sizes into the smallest rectangle possible in a fairly optimal way?
Minimum exact cover of grid with squares; extra cuts
Algorithm for finding the fewest rectangles to cover a set of rectangles without overlapping
https://mathoverflow.net/questions/244718/algo-for-covering-maximum-surface-of-a-polygon-with-rectangles
https://mathoverflow.net/questions/105837/get-largest-inscribed-rectangle-of-a-concave-polygon
https://mathoverflow.net/questions/80665/how-to-cover-a-set-in-a-grid-with-as-few-rectangles-as-possible
Converting monochrome image to minimum number of 2d shapes
I also read on Covering rectilinear polygons with axis-parallel rectangles.
I even found a code here: https://github.com/codecombat/codecombat/blob/6009df26de7c7938c0af2122ffba72c07123d172/app/lib/world/world_utils.coffee#L94-L148
I tested multiple approaches but in the end none were as fast as I needed or generated a reasonable amount of rectangles. So for now I went with a different approach.

how to calculate the number of specified colored pixels using GLSL?

I have a grayscale texture (8000*8000) , the value of each pixel is an ID (actually, this ID is the ID of triangle to which the fragment belongs, I want to using this method to calculate how many triangles and which triangles are visible in my scene).
now I need to count how many unique IDs there are and what are them. I want to implement this with GLSL and minimize the data transfer between GPU RAM and RAM.
The initial idea I come up with is to use a shader storage buffer, bind it to an array in GLSL, its size is totalTriangleNum, then iterate through the ID texture in shader, increase the array element by 1 that have index equal to ID in texture.
After that, read the buffer to OpenGL application and get what I want. Is this a efficient way to do so? Or are there some better solutions like compute-shader (well I'm not familiar with it) or something else.
I want to using this method to calculate how many triangles and which triangles are visible in my scene)
Given your description of your data let me rephrase that a bit:
You want to determine how many distinct values there are in your dataset, and how often each value appears.
This is commonly known as a Histogram. Unfortunately (for you) generating histograms are among the problems not that trivially solved on GPUs. Essentially you have to divide down your image into smaller and smaller subimages (BSP, quadtree, etc.) until divided down to single pixels on which you perform the evaluation. Then you backtrack propagating up the sub-histograms, essentially performing an insertion or merge sort on the histogram.
Generating histograms with GPUs is still actively researched, so I suggest you read up on the published academic works (usually accompanied with source code). Keywords: Histogram, GPU
This one is a nice paper done by the AMD GPU researchers: https://developer.amd.com/wordpress/media/2012/10/GPUHistogramGeneration_preprint.pdf

Draw large number (10M) of 2d polygons with opengl

I'm working on a CAD software which need to show circuit blueprint containing more than 10M 2d polygons. Each polygon is simple, 95% of them are only rectangles, others have fewer than 10 vertexes.
In order to show the whole design, I will need to create a huge vertex buffer which will definitely blow up the graphics memory limit. However, since most of the polygons won't be seen clearly at that scale, I'm thinking of using some pre screening algorithm to minimize the polygons to draw. But if I do so, so many polygons (each of them won't be larger than one pixel) will be gone, then the final image will be wrong.
Another thought will be to separate polygons into groups each of which will be strongly connected (touching), then construct a large polygon for each group. Some level of detail algorithm may be used to shrink the points without changing the shapes. Not sure how fast these algorithms are and if I need to pre calculate for different scale level.
Is there any standard way to deal with this problem? I'm pretty sure it has been solved lots of times...
To clarify, we need to make this work on OpenGL 2.1.
You're targeting OpenGL-2.1 so client side vertex arrays are available. Which effectively means: You don't have to upload anything to the GPU at all, the data is fetched from your programs address space on demand.
Of course 10M triangles is not a lot; some professions use programs in which a single frame ends up with 1G triangles. The amount of data required is easy enough to calculate:
10M # number of primitives
* 4 # number of vertices in a quad
* 4B # sizeof GLfloat
* 2 # number of elements in a 2D vector
= 320MB
That's not a lot. Most GPUs you can buy these days come with at least 512MiB of memory, where this fits nicely. However even if your GPU doesn't have as much memory available, OpenGL's memory model is abstract and data is swapped to and from the GPU as needed.

Find out if point is inside one of N (possibly overlapping) rectangles in less than O(N)

I have an image, and I want to show tooltips when mouse moves over certain rectangular areas. The rectangular areas can be up to 1000. However, just checking each rectangle if the point is in it, which is O(N), makes the interface unresponsive when moving the mouse.
Is there a way to do it in less than O(N)? I can sort the rectangles beforehand (I'm assuming it would be needed). The rectangles might be (very rarely) overlapping, but no more than 4-5 rectangles can overlap the same area. In that case I might need to get a list of all the rectangles, but even just any of them would still be good enough.
But I'm assuming that this problem has already been solved by window managers, etc.
It sounds like you want to be storing your rectangles within an R-Tree and then querying that. There are a few implementations available:
JTS Topology Suite (Java)
Net Topology Suite (.Net)
GeoTools (.Net)
Check out their STRtree classes.
A faster and simpler (though less memory efficient) method than a tree for images (and web pages that can be rendered onto reasonably small images) is to use a stencil. i.e. if you have an image of x by y pixels, create a two dimensional array of size x by y and populate it with your tool tip IDs. This has a search speed from pixel position to ID of O(1) (my favourite O)
If the rectangle are axis-aligned, you can avoid specialised data structures.
First subdivide the space in one dimension, e.g. subdividing the screen horizontally into vertical strips. Each rectangle may be in multiple strips. Then you subdivide each strip depending on the rectangles that overlap that strip. The search then involves two O(log n) binary searches or binary trees - one to identify the strip, one to identify which rectangle.
This is a recognised spatial data structure, but to me it doesn't really count - it's just using normal binary trees. You could even do it with an std::map<int, std::map<int, int>>.
But there's actually an option supporting O(1) searches, which is called "pixel picking". Basically, draw the rectangles in an off-screen bitmap, each rectangle in a different colour, and frontmost rectangles last as you would for normal drawing (painters algorithm). You can identify which rectangle is frontmost at any point by simply reading that pixel.
Extra bonus - your graphics card may even accelerate drawing the rectangles, so you don't need to worry too much about redrawing when the set of rectangles changes (which obviously isn't included in that O(1)). It's a bit expensive in memory but, on a modern machine, you may not care about that.
Use a spatial search data structure such as the quad-tree.
You will need to add your rectangles to the tree beforehand, but the average search will be fast. In the worst case you may still have O(N) though.

How can I scale down an array of raw rgb data on a 16 bit display

I have an array of raw rgb data on a 16 bit display with dimension of 320 * 480. The size of the array is 320*480*4 = 6144000.
I would like to know how can I scale this down (80 * 120) without losing image quality?
I found this link about scaling image in 2D array, but how can I apply that to my array of 16 bit display? It is not a 2D array (because of it has 16 bit color).
Image scaling and rotating in C/C++
Thank you.
If you are scaling down a big image to a smaller one, you WILL lose image quality.
The question, then, is how to minimize that loss.
There are many algorithms that do this, each with strengths and weaknesses.
Typically you will apply some sort of filter to your image, such as Bilinear or Nearest Neighbor. Here is a discussion of such filters in the context of ImageMagick.
Also, if the output is going to be less than 16 bits per pixel, you need to do some form of Color Quantization.
I assume that you mean a 16 bit rgb display, not a display that has each color (red, green, and blue) as 16 bits. I also assume you know how your r, g, and b values are encoded in that 16 bit space, because there are two possibilities.
So, assuming you know how to split your color space up, you can now use a series of byte arrays to represent your data. What becomes a tricky decision is whether to go with byte arrays, because you have a body of algorithms that can already do the work on those arrays but will cost you a few extra bits per byte that you may not be able to spend, or to keep everything crammed into that 16 bit format and then do the work on the appropriate bits of each 16 bit pixel. Only you can really answer that question; if you have the memory, I'd opt for the byte array approach, because it's probably faster and you'll get a little extra precision to make the images look smooth(er) in the end.
Given those assumptions, the question is really answerable by how much time you have on your device. If you have a very fast device, you can implement a Lanczos resampling. If you have a less fast device, bicubic interpolation works very well as well. If you have an even slower device, bilinear interpolation is your friend.
If you really have no speed, I'd do the rescaling down in some external application, like photoshop, and save a series of bitmaps that you load as you need them.
There are plenty of methods of scaling down images, but none can guarantee not losing "quality". Ultimately information is lost during the rescaling process.
You have 16bit colors = 2bytes, but in your calculations you use 4 multiplier.
Maybe you don't needed reducing image size?
in general it is impossible to scale raster image without loosing quality. Some algorithms make scaling almost without visible quality loosing.
Since you are scaling down by a factor of 4, each 4x4 block of pixels in your original image will correspond to a single pixel in your output image. You can then loop through each 4x4 block in the original image and then reduce this to a single pixel. A simple way (perhaps not the best way) to do this reduction could be to take the average or median of the RGB components.
You should note that you cannot do image scaling without losing image quality unless for all the blocks in the original image, each pixel is the exact same colour (which is unlikely).