How to convert pixels into indices - c++

The problem it's I need to change a matrix and I just have acess to these positions in pixels x and y, how can I convert x and y into an indice ?
E.g :
char *map[20][17] = {
"WWWWWWWWWWWWWWWW",
"WFFFFFFFFFFFFFFW",
"WFWWWWWFFWWWWWFW",
"WFFFFFFFFFFFFFFW",
"WFWWWWWFFWWWWWFW",
"WFFFFFFFFFFFFFFW",
"WFWWWWWWWWWWWWFW",
"WFFFFFFWWFFFFFFW",
"WFFFWFFWWFFWFFFW",
"WFWWWFFFFFFWWWFW",
"WFWFFFWWWWFFFWFW",
"WFFFWFFFFFFWFFFW",
"WFWWWFWFFWFWWWFW",
"WFFFWFWWWWFWFFFW",
"WFFFFFFFFFFFFFFW",
"WFFFWWWWWWWWFFFW",
"WFWFFFFFFFFFFWFW",
"WFWWWWWFFWWWWWFW",
"WFFFFFFFFFFFFFFW",
"WWWWWWWWWWWWWWWW"};
int x_pac = 240, y_pac = 360;
Using x_pac and y_pac to access some position on map, in this case each one of characters have height = 30 and width = 30.

you can get the indices simply dividing x-y positions by width and height. row = y_pac / height. col = x_pac / width

I think I can visualize your input.
So you have a map containing a collection of bitmap "image" characters.
Where the size of each bitmap "image" characters can be varied (eg. 30x30).
Say for this example: you have 4x4 char map and each character has a dimension of 6x6.
If you want to access a specific pixel in a specific character, use this formula:
// matrix dimension
matrix_row = <row>
matrix_col = <col>
// bitmap dimension
char_row = <char_row>
char_col = <char_col>
num_pixels = char_row * char_col
// get specific "character" in grid
character_index = ((matrix_row - 1) * matrix_col) * num_pixels
// get specific "pixel" in character
pixel = character_index * ((char_row - 1) * char_col + pixel_offset)

Related

Transform images with bezier curves

I'm using this article: nonlingr as a font to understand non linear transformations, in the section GLYPHS ALONG A PATH he explains how to use a parametric curve to transform an image, i'm trying to apply a cubic bezier to an image, however i have been unsuccessfull, this is my code:
OUT.aloc(IN.width(), IN.height());
//get the control points...
wVector p0(values[vindex], values[vindex+1], 1);
wVector p1(values[vindex+2], values[vindex+3], 1);
wVector p2(values[vindex+4], values[vindex+5], 1);
wVector p3(values[vindex+6], values[vindex+7], 1);
//this is to calculate t based on x
double trange = 1 / (OUT.width()-1);
//curve coefficients
double A = (-p0[0] + 3*p1[0] - 3*p2[0] + p3[0]);
double B = (3*p0[0] - 6*p1[0] + 3*p2[0]);
double C = (-3*p0[0] + 3*p1[0]);
double D = p0[0];
double E = (-p0[1] + 3*p1[1] - 3*p2[1] + p3[1]);
double F = (3*p0[1] - 6*p1[1] + 3*p2[1]);
double G = (-3*p0[1] + 3*p1[1]);
double H = p0[1];
//apply the transformation
for(long i = 0; i < OUT.height(); i++){
for(long j = 0; j < OUT.width(); j++){
//t = x / width
double t = trange * j;
//apply the article given formulas
double x_path_d = 3*t*t*A + 2*t*B + C;
double y_path_d = 3*t*t*E + 2*t*F + G;
double angle = 3.14159265/2.0 + std::atan(y_path_d / x_path_d);
mapped_point.Set((t*t*t)*A + (t*t)*B + t*C + D + i*std::cos(angle),
(t*t*t)*E + (t*t)*F + t*G + H + i*std::sin(angle),
1);
//test if the point is inside the image
if(mapped_point[0] < 0 ||
mapped_point[0] >= OUT.width() ||
mapped_point[1] < 0 ||
mapped_point[1] >= IN.height())
continue;
OUT.setPixel(
long(mapped_point[0]),
long(mapped_point[1]),
IN.getPixel(j, i));
}
}
Applying this code in a 300x196 rgb image all i get is a black screen no matter what control points i use, is hard to find information about this kind of transformation, searching for parametric curves all i find is how to draw them, not apply to images. Can someone help me on how to transform an image with a bezier curve?
IMHO applying a curve to an image sound like using a LUT. So you will need to check for the value of the curve for different image values and then switch the image value with the one on the curve, so, create a Look-Up-Table for each possible value in the image (e.g : 0, 1, ..., 255, for a gray value 8 bit image), that is a 2x256 matrix, first column has the values from 0 to 255 and the second one having the value of the curve.

Show more points then resolution

I am drawing a graph with 2000+ points to a pdf file. The resolution of the pdf is 612 x 792. I can only draw 612 points to the pdf because the width is 612. I am mapping 1 point to 1 pixel. How can I plot all 2000+ samples to the pdf. I am using this lib http://www.vulcanware.com/cpp_pdf/index.html.
Option 1: Scale the points, using x = (x * 612) / 2000. This will mean that if 2 points are close to each other (including "similar y") they will overwrite each other.
Option 2: Treat each point as a square; and calculate floating point values for the "left edge x" and "right edge x" that have been scaled (left_x = ( (x-width/2.0) * 612.0) / 2000.0; right_x = ( (x+width/2.0) * 612.0) / 2000.0;), and draw the square using anti-aliasing, by calculating "area of destination pixel that the square overlaps" for each destination pixel that overlaps with the square. In this case you will need to do "dest_pixel = max(dest_pixel + area, 1);" to clamp pixel values when squares overlap.
Option 3: Rotate the whole thing 90 degrees so that "x axis" goes vertically down the page (and can be split across multiple pages if necessary); and if this causes a problem for y then use one of the options above for y.
Note that "option 2" can be done in both (vertical and horizontal) directions at the same time. To do this, start by determining the edges of the square, like:
left_x = point_x / MAX_SRC_X * MAX_DEST_X;
right_x = (point_x + 1) / MAX_SRC_X * MAX_DEST_X;
top_y = point_y / MAX_SRC_Y * MAX_DEST_Y;
bottom_y = (point_y + 1) / MAX_SRC_Y * MAX_DEST_Y;
Then have a "for each row that is effected" loop that calculates how much each row is effected, like:
for(int y = top_y; y < bottom_y; y++) {
row_top = fmax(y, top_y);
row_bottom = fmin(y+1, bottom_y);
row_weight = row_bottom - row_top;
Then have a similar "for each column that is effected" loop, like:
for(int x = left_x; x < right_x; x++) {
column_left = fmax(x, left_x);
column_right = fmin(x+1, right_x);
column_weight = column_right - column_left;
Then calculate the area for the pixel, set the pixel, and complete the loops:
dest_pixel_area = row_weight * column_weight;
pixel[y][x].red = min(pixel[y][x].red + dest_pixel_area * red, MAX_RED);
pixel[y][x].green = min(pixel[y][x].green + dest_pixel_area * green, MAX_GREEN);
pixel[y][x].blue = min(pixel[y][x].blue + dest_pixel_area * blue, MAX_BLUE);
}
}
Note: All code above is untested and simplified. It can be faster to break the loops up into "first line/column; loop for middle area only; then last line/column" to remove most of the fmin/fmax.
If you only need to do this in one direction, delete the parts for the direction you don't need and use 1.0 for the corresponding row_weight or column_weight.

Render a portion of 1d array as 2D?

I am trying to render a bunch of quads on a screen, but I cannot get it to render correctly.
I have a 1D array that is 10000 (100x100) in size and holds texture ids:
mapping = { 1, 22, 55, 28, 95, 105, ...}
The texture file contains 512x512 pixels, with 16x16 pixels for each image. So, that is 32x32 images in total. And the texture ids correspond by going left to right starting from 0:
0 1 2 3 ... 31
32 33 34 35 ... 63
............... 1023
Given a screen resolution of 800x600 pixels, I want to render only a subset of my quads that will fit on this resolution, so I don't want to draw all 10000 quads from my 1D array.
To draw from the (0,0) tile, this is what I have:
for (int j = 0; j < 37; j++) { // 600/16 = 37
for(int i = 0; i < 50; i++) { // 800/16 = 50
int quadIndex = j*800/16 + i;
int textureID = mapping[quadIndex];
int x = (textureID % 512) * 16;
int y = (textureID / 512) * 16;
// Take image from texture starting at (x,y) and draw on screen at (i, j)
draw(i, j, x, y);
}
}
The problem with this is the quadIndex is not accurate. It draws the first row correctly, but the second row is just a continuation of the first row instead of the actual second row. Basically the first row is overflowing onto the second row, and it's throwing everything off.
I am sure it is because I can calculating the quadIndex incorrectly, but I don't know what the solution is.
Also, as an added bonus, how would I specify rendering from any (a,b) offset instead of always from (0,0)? That is, with my 1D array, I want to draw from (4,4) onto my 800x600 resolution.
You should use width of source array, not screen width. As far as I understand, it is width of mapping = 100?
int quadIndex = j * 100 + i;

Access R,G and B pixel values using a pointer to image data

I have read an image in Mat format.
Mat image = imread("image.png", 1);
I declare a pointer to its data using
unsigned char *ptr_source = image.data
Now, I want to access the value of R,G and B values at each pixel in a for loop. I already know the method to do it with img.at<Veb3b>(i,j) or similar things but now, I have to do it using a pointer of unsigned char type.
uchar R_value = ptr_source[ i*?? + ??? ];
uchar G_value = ptr_source[ i*?? + ??? ];
uchar B_value = ptr_source[ i*?? + ??? ];
IMPORTANT: Some people here have mentioned to use the following:
unsigned char *input = (unsigned char*)(img.data);
for(int j = 0;j < img.rows;j++){
for(int i = 0;i < img.cols;i++){
unsigned char b = input[img.step * j + i ] ;
unsigned char g = input[img.step * j + i + 1];
unsigned char r = input[img.step * j + i + 2];
}
}
which makes sense to me as per the openCV docs but unfortunately it is not working in my case. The other method posted at SO says to use the following:
uchar b = frame.data[frame.channels()*(frame.cols*y + x) + 0];
uchar g = frame.data[frame.channels()*(frame.cols*y + x) + 1];
uchar r = frame.data[frame.channels()*(frame.cols*y + x) + 2];
Basic Question: Though, it seems to be working but I do not understand it logically. Why do we need to multiply (frame.cols*y + x) with frame.channels() ??
The cv::Mat::channels() method returns the number of channels in an image.
In a 8UC3 three-channel color image, channels() returns 3, and the pixels are stored in consecutive byte-triplets: BGRBGRBGRBGRBGR....
To access pixel (x,y) given a unsigned char* ptr_source pointer, you need to calculate the pixel offset. The image width is frame.cols. Each pixel is channels() == 3 bytes, so the pixel's unsiged char* offset will be ptr_source + frame.channels()*(frame.cols*y + x). This unsigned char* would usually be the blue channel with the following 2 chars the green and red.
For example, given a 3x4 image, the pixels in memory would look like this (spaces for clarity only):
r\c 0 1 2
0 BGR BGR BGR
1 BGR BGR BGR
2 BGR>BGR<BGR
3 BGR BGR BGR
So if you count bytes you'll see that the blue channel byte of pixel (1,2) is exactly at byte offset 3*(2*3+1) = 21
It is actually advisable to use img.step instead of the raw computation since some images have padding at the end of each pixel row so that it is not always true that img.step[0] == img.channels()*img.cols.
In this case you should use ptr_source[img.step[0]*y + img.channels()*x].
Additionally, your question assumes that the pixel depth is 8U which may not be correct for all images. If it is not, you will need to multiply everything by the depth (bytes per pixel) as well.
And this is essentially what cv::Mat:at<> does...

How to extract a subimage from a 1-dimension array?

I have an image represented by a 1-dimension array (char[]). Image height is H, image width is W, and I would like to extract a subimage starting in (dx,dy) and which dimensions are (dW,dH)
This seems not to work :
subimage(i,j) = image[(j+dy*W) * (W+i+dx)]
Can somebody help?
The formula for a particular pixel in an image stored a 1-dimensional array with the stride equal to the image width is:
pixel(x,y) = image[(y * width) + x]
So the formula you're looking for is (in pseudo-code):
subimage(i,j) = image[((j+dy)*W) + (i+dx)]
Iterate j over 0 to dH and i over 0 to dW.