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

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.

Related

How to flatten 3D matrices into arrays?

I'm trying to flatten 3D matrices of arbitrary sizes into arrays such that values can be retrieved from arrays based on the spatial indexes i, j, and k. Clearly, each array index will have to be unique. I've tried setting the array index to int idx = i + width * (j + height * k), but that's not unique because (1,0,0) and (0,1,0) would give the same index if width == 1. Does anyone know of a better way to index or flatten 3D matrices?
Your formula is OK, because if width == 1, then j must be always 0

How to convert pixels into indices

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)

How to convert a 3D point cloud to a depth image?

For my work I have to convert a point cloud to a grey scale (depth) image meaning that the z coordinate of each XYZ point in the cloud represents a shade of grey. For mapping a Z coordinate from the [z_min, z_max] interval to the [0..255] interval I used the map function of Arduino:
float map(float x, float in_min, float in_max, float out_min, float out_max)
{ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
With that done I need to write the result to an image, the problem being that the clouds that I have can have millions of points so I can't just write them 1 by 1 to an image in order. Let's say that I have 3000x1000 ordered XY points. How would I do if I wanted to write them to a 700x300 pixels image? I hope the question is clear, thanks in advance for answering.
I have managed to find a solution to my problem. It is a fairy long algorithm for stack overflow but bear with me. The idea is write a vector of XY grey scale points as a pgm file.
Step 1: cloud_to_greyscale - function that converts an XYZ Point Cloud into a vector of XY grey scale points and that receives a cloud as a parameter:
for each point pt in cloud
point_xy_greyscale.x <- pt.x
point_xy_greyscale.y <- pt.y
point_xy_greyscale.greyscale <- map(pt.z, z_min, z_max, 0, 255)
greyscale_vector.add(point_xy_greyscale)
loop
return greyscale_vector
Step 2: greyscale_to_image - function that writes the previously returned vector as a greyscale_image, a class that has a width, a height and a _pixels member corresponding to a double dimensional array of unsigned short usually. The function receives the following parameters: a greyscale_vector (to be turned into the image) and an x_epsilon that will help us delimit the x pixel coordinates for our points, knowing that the x point coordinates are floats (and thus not suitable as array indices).
A little background info: I work on something called widop clouds so in my 3D space x is the width, y is the depth and z is the height. Also worth noting is the fact that y is an integer so for my problem, the height of the image is easy to find: it's y_max - y_min. To find the width of the image, follow the algorithm below and if it isn't clear I will answer any questions and I'm open to suggestions.
img_width <- 0; // image width
img_height <- y_max - y_min + 1 // image height
// determining image width
for each point greyscale_xy_point in greyscale_vector
point_x_cell <- (pt.x - x_min) * x_epsilon * 10
if point_x_cell > img_width
img_width <- point_x_cell + 1
loop
// defining and initializing image with the calculated height and width
greyscale_img(img_width, img_height)
// initializing greyscale image points
for y <- 0 to greyscale_img.height
for x <- 0 to greyscale_img.width
greyscale_img[y][x] = 0
loop
loop
// filling image with vector data
for each point point_xy_greyscale in greyscale_vector
image_x = (point_xy_greyscale.x - x_min) * x_epsilon * 10
image_y = point_xy_greyscale.y - y_min
greyscale_image[image_y][image_x] = point_xy_greyscale.greyscale
loop
return greyscale_image
The only thing left to do is to write the image to the file, but that is easy to do, you can just find the format rules in the previous link related to the pgm format. I hope this helps someone.
EDIT_1: I added a picture of the result. It is supposed to be a railway and the reason it's fairly dark is that there are some objects that are tall so ground objects are darker.
depth image of railway

How i can take the average of 100 image using opencv?

i have 100 image, each one is 598 * 598 pixels, and i want to remove the pictorial and noise by taking the average of pixels, but if i want to use Adding for "pixel by pixel"then dividing i will write a loop until 596*598 repetitions for one image, and 598*598*100 for hundred of image.
is there a method to help me in this operation?
You need to loop over each image, and accumulate the results. Since this is likely to cause overflow, you can convert each image to a CV_64FC3 image, and accumualate on a CV_64FC3 image. You can use also CV_32FC3 or CV_32SC3 for this, i.e. using float or integer instead of double.
Once you have accumulated all values, you can use convertTo to both:
make the image a CV_8UC3
divide each value by the number of image, to get the actual mean.
This is a sample code that creates 100 random images, and computes and shows the
mean:
#include <opencv2\opencv.hpp>
using namespace cv;
Mat3b getMean(const vector<Mat3b>& images)
{
if (images.empty()) return Mat3b();
// Create a 0 initialized image to use as accumulator
Mat m(images[0].rows, images[0].cols, CV_64FC3);
m.setTo(Scalar(0,0,0,0));
// Use a temp image to hold the conversion of each input image to CV_64FC3
// This will be allocated just the first time, since all your images have
// the same size.
Mat temp;
for (int i = 0; i < images.size(); ++i)
{
// Convert the input images to CV_64FC3 ...
images[i].convertTo(temp, CV_64FC3);
// ... so you can accumulate
m += temp;
}
// Convert back to CV_8UC3 type, applying the division to get the actual mean
m.convertTo(m, CV_8U, 1. / images.size());
return m;
}
int main()
{
// Create a vector of 100 random images
vector<Mat3b> images;
for (int i = 0; i < 100; ++i)
{
Mat3b img(598, 598);
randu(img, Scalar(0), Scalar(256));
images.push_back(img);
}
// Compute the mean
Mat3b meanImage = getMean(images);
// Show result
imshow("Mean image", meanImage);
waitKey();
return 0;
}
Suppose that the images will not need to undergo transformations (gamma, color space, or alignment). The numpy package lets you do this quickly and succinctly.
# List of images, all must be the same size and data type.
images=[img0, img1, ...]
avg_img = np.mean(images, axis=0)
This will auto-promote the elements to float. If you want the as BGR888, then:
avg_img = avg_img.astype(np.uint8)
Could also do uint16 for 16 bits per channel. If you are dealing with 8 bits per channel, you almost certainly won't need 100 images.
Firstly- convert images to floats. You have N=100 images. Imagine that a single image is an array of average pixel values of 1 image. You need to calculate an array of average pixel values of N images.
Let A- array of average pixel values of X images, B - array of average pixel values of Y images. Then C = (A * X + B * Y) / (X + Y) - array of average pixel values of X + Y images. To get better accuracy in floating point operations X and Y should be approximately equal
You may merge all you images like subarrays in merge sort. In you case merge operation is C = (A * X + B * Y) / (X + Y) where A and B are arrays of average pixel values of X and Y images

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...