Copying R8G8B8A8 image to R8G8B8 - c++

I'm trying to convert an R8G8B8A8 image to R8G8B8 image, what I get right now is an image, but with a lot of scan lines, I have byters per pixels is 4 bytes, 32bit.
The image buffer is of type unsigned char [width*height*4] that's the source and the destination is unsigned char [width*height*3].
int j = 0;
int i = 0;
for (int k = 0; k < (width*height); k++)
{
for(int b = 0; b < 3; b++)
{
dst[i + b] = src[j + b];
}
i+=3;
j+=4;
}

Probably the destination image requires lines aligned on a 4 bytes boundary:
for(unsigned int y(0); y != height; ++y)
{
unsigned int sourceStart(y * width * 4);
unsigned int destStart(y * ((width * 3 + 3) & 0xfffffffc) ); // align on 4 bytes
for(unsigned int x(0); x != width; ++x)
{
for(unsigned int color(0); color != 3; ++color)
{
dst[destStart++] = src[sourceStart++];
}
++sourceStart; // account for 4th byte in source
}
}

You can do this:
for (int k = 0; k < width*height; k++)
{
for(int b = 0; b < 3; b++)
{
dst[k*3 + b] = src[k*4 + b];
}
}

Related

How to reorder raw image color data to achieve a specific 2 by 2 format from four images? (C++)

I have the raw color data for four images, let's call them 1, 2, 3, and 4. I am storing the data in an unsigned char * with allocated memory. Individually I can manipulate or encode the images but when trying to concatenate or order them into a single image it works but takes more time than I would like.
I would like to create a 2 by 2 of the raw image data to encode as a single image.
1 2
3 4
For my example each image is 400 by 225 with RGBA (360000 bytes). Iim doing a for loop with memcpy where
for (int j = 0; j < 225; j++)
{
std::memcpy(dest + (j * (400 + 400) * 4), src + (j * 400 * 4), 400 * 4); //
}
for each image with an offset for the starting position added in (the example above would only work for the top left of course).
This works but I'm wondering if this is a solved problem with a better solution, either in an algorithm described somewhere or a small library.
#include <iostream>
const int width = 6;
const int height = 4;
constexpr int n = width * height;
int main()
{
unsigned char a[n], b[n], c[n], d[n];
unsigned char dst[n * 4];
int i = 0, j = 0;
/* init data */
for (; i < n; i++) {
a[i] = 'a';
b[i] = 'b';
c[i] = 'c';
d[i] = 'd';
}
/* re-order */
i = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++, i++, j++) {
dst[i ] = a[j];
dst[i + width] = b[j];
dst[i + n * 2 ] = c[j];
dst[i + n * 2 + width] = d[j];
}
i += width;
}
/* print result */
i = 0;
for (int y = 0; y < height * 2; y++) {
for (int x = 0; x < width * 2; x++, i++)
std::cout << dst[i];
std::cout << '\n';
}
return 0;
}

Generate gradient with CImg and dynamic array

I'm trying to generate png with different resolution. But if i use dynamic array its generate only gray area. This is source of my code (C++ 16 bit grayscale gradient image from 2D array)
void generate_horizontal_gradient(char fileName[], int width, int height, int offset, bool direction)
{
unsigned short** buffer = new unsigned short* [height];
for (int i = 0; i < height; i++)
{
buffer[i] = new unsigned short[width];
}
for (int i = 0; i < height; i++)
{
unsigned short temp_data = 65535;
if (direction == true) {
for (int j = width; j > 0; j--)
{
buffer[i][j] = temp_data;
if (j < width - offset)
{
temp_data -= 65535 / (width - offset);
}
}
}
else
{
for (int j = 0; j < width; j++)
{
buffer[i][j] = temp_data;
if (j > offset)
{
temp_data -= 65535 / (width - offset);
}
}
}
}
auto hold_arr = (unsigned short*) &buffer[0][0];
cimg_library::CImg<unsigned short> img(hold_arr, width, height);
img.save_png(fileName);
}
Apparently I don’t understand something yet in two-dimensional arrays. Solved the problem through a one-dimensional array:
void generate_horizontal_gradient(char fileName[], int width, int height, int offset, bool direction)
{
unsigned short* buffer = new unsigned short[height * width];
//Add values to array.
for (int i = 0; i < height; i++)
{
unsigned short temp_data = 65535;
if (direction == true) {
for (int j = width; j > 0; j--)
{
buffer[i* width +j] = temp_data;
if (j < width - offset) temp_data -= 65535 / (width - offset);
}
}
else
{
for (int j = 0; j < width; j++)
{
buffer[i * width + j] = temp_data;
if (j > offset) temp_data -= 65535 / (width - offset);
}
}
}
unsigned short* hold_arr = (unsigned short*)& buffer[0*0];
cimg_library::CImg<unsigned short> img(buffer, width, height);
img.save_png(fileName);
}

Alpha-trimmed filter troubles

I am trying to make an alphatrimmed filter in openCV library. My code is not working properly and the resultant image is not looking as image after filtering.
The filter should work in the following way.
Chossing some (array) of pixels in my example it is 9 pixels '3x3' window.
Ordering them in increasing way.
Cutting our 'array' both sides for alpha-2.
calculating arithmetic mean of remaining pixels and inserting them in proper place.
int alphatrimmed(Mat img, int alpha)
{
Mat img9 = img.clone();
const int start = alpha/2 ;
const int end = 9 - (alpha/2);
//going through whole image
for (int i = 1; i < img.rows - 1; i++)
{
for (int j = 1; j < img.cols - 1; j++)
{
uchar element[9];
Vec3b element3[9];
int k = 0;
int a = 0;
//selecting elements for window 3x3
for (int m = i -1; m < i + 2; m++)
{
for (int n = j - 1; n < j + 2; n++)
{
element3[a] = img.at<Vec3b>(m*img.cols + n);
a++;
for (int c = 0; c < img.channels(); c++)
{
element[k] += img.at<Vec3b>(m*img.cols + n)[c];
}
k++;
}
}
//comparing and sorting elements in window (uchar element [9])
for (int b = 0; b < end; b++)
{
int min = b;
for (int d = b + 1; d < 9; d++)
{
if (element[d] < element[min])
{
min = d;
const uchar temp = element[b];
element[b] = element[min];
element[min] = temp;
const Vec3b temporary = element3[b];
element3[b] = element3[min];
element3[min] = temporary;
}
}
}
// index in resultant image( after alpha-trimmed filter)
int result = (i - 1) * (img.cols - 2) + j - 1;
for (int l = start ; l < end; l++)
img9.at<Vec3b>(result) += element3[l];
img9.at<Vec3b>(result) /= (9 - alpha);
}
}
namedWindow("AlphaTrimmed Filter", WINDOW_AUTOSIZE);
imshow("AlphaTrimmed Filter", img9);
return 0;
}
Without actual data, it's somewhat of a guess, but an uchar can't hold the sum of 3 channels. It works modulo 256 (at least on any platform OpenCV supports).
The proper solution is std::sort with a proper comparator for your Vec3b :
void L1(Vec3b a, Vec3b b) { return a[0]+a[1]+a[2] < b[0]+b[1]+b[2]; }

QImage::setPixel: coordinate out of range

i am beginner in QT
i try to open binary file and draw it pixel by pixel
i got this warning when i was debugging
QImage::setPixel: coordinate (67,303) out of range
QImage::setPixel: coordinate (67,306) out of range
QImage::setPixel: coordinate (67,309) out of range
QImage::setPixel: coordinate (67,312) out of range
and this is the code
unsigned char* data = new unsigned char[row_padded];
unsigned char tmp;
QImage myImage;
myImage = QImage(width, height, QImage::Format_RGB888);
for(int i = 0; i < height; i++)
{
fread(data, sizeof(unsigned char), row_padded, file);
for(int j = 0; j < width*3; j += 3)
{
// Convert (B, G, R) to (R, G, B)
tmp = data[j];
data[j] = data[j+2];
data[j+2] = tmp;
myImage.setPixel((width*3)-j, height-i, RGB((int)data[j],(int)data[j+1],(int)data[j+2]));
}
}
thanks in advance :)
You incorrectly calculate x and y coordinate on this line:
myImage.setPixel((width*3)-j, height-i, RGB((int)data[j],(int)data[j+1],(int)data[j+2]));
x should be instead:
width - j / 3 - 1
y should be
height - i - 1
or maybe it is better to use another variable for x to avoid division:
for(int i = 0; i < height; i++)
{
fread(data, sizeof(unsigned char), row_padded, file);
int x = width;
for(int j = 0; j < width*3; j += 3)
{
// Convert (B, G, R) to (R, G, B)
tmp = data[j];
data[j] = data[j+2];
data[j+2] = tmp;
myImage.setPixel(--x, height-i-1, RGB((int)data[j],(int)data[j+1],(int)data[j+2]));
}
}
Suggestions: it is better to define variable right before it is used:
unsigned char tmp = data[j];
data[j] = data[j+2];
data[j+2] = tmp;
or even better
std::swap( data[j], data[j+2] );

OpenCV get pixel channel value from Mat image

Maybe I'm not looking hard enough, but everything seems to want me to use an array. Thus, how do I get the channel value for a particular pixel for foo if foo is something like Mat foo = imread("bar.png")?
Assuming the type is CV_8UC3 you would do this:
for(int i = 0; i < foo.rows; i++)
{
for(int j = 0; j < foo.cols; j++)
{
Vec3b bgrPixel = foo.at<Vec3b>(i, j);
// do something with BGR values...
}
}
Here is the documentation for Vec3b. Also, don't forget OpenCV stores things internally as BGR not RGB.
EDIT :
For performance reasons, you may want to use direct access to the data buffer in order to process the pixel values:
Here is how you might go about this:
uint8_t* pixelPtr = (uint8_t*)foo.data;
int cn = foo.channels();
Scalar_<uint8_t> bgrPixel;
for(int i = 0; i < foo.rows; i++)
{
for(int j = 0; j < foo.cols; j++)
{
bgrPixel.val[0] = pixelPtr[i*foo.cols*cn + j*cn + 0]; // B
bgrPixel.val[1] = pixelPtr[i*foo.cols*cn + j*cn + 1]; // G
bgrPixel.val[2] = pixelPtr[i*foo.cols*cn + j*cn + 2]; // R
// do something with BGR values...
}
}
Or alternatively:
int cn = foo.channels();
Scalar_<uint8_t> bgrPixel;
for(int i = 0; i < foo.rows; i++)
{
uint8_t* rowPtr = foo.row(i);
for(int j = 0; j < foo.cols; j++)
{
bgrPixel.val[0] = rowPtr[j*cn + 0]; // B
bgrPixel.val[1] = rowPtr[j*cn + 1]; // G
bgrPixel.val[2] = rowPtr[j*cn + 2]; // R
// do something with BGR values...
}
}
The below code works for me, for both accessing and changing a pixel value.
For accessing pixel's channel value :
for (int i = 0; i < image.cols; i++) {
for (int j = 0; j < image.rows; j++) {
Vec3b intensity = image.at<Vec3b>(j, i);
for(int k = 0; k < image.channels(); k++) {
uchar col = intensity.val[k];
}
}
}
For changing a pixel value of a channel :
uchar pixValue;
for (int i = 0; i < image.cols; i++) {
for (int j = 0; j < image.rows; j++) {
Vec3b &intensity = image.at<Vec3b>(j, i);
for(int k = 0; k < image.channels(); k++) {
// calculate pixValue
intensity.val[k] = pixValue;
}
}
}
`
Source : Accessing pixel value
The pixels array is stored in the "data" attribute of cv::Mat. Let's suppose that we have a Mat matrix where each pixel has 3 bytes (CV_8UC3).
For this example, let's draw a RED pixel at position 100x50.
Mat foo;
int x=100, y=50;
Solution 1:
Create a macro function that obtains the pixel from the array.
#define PIXEL(frame, W, x, y) (frame+(y)*3*(W)+(x)*3)
//...
unsigned char * p = PIXEL(foo.data, foo.rols, x, y);
p[0] = 0; // B
p[1] = 0; // G
p[2] = 255; // R
Solution 2:
Get's the pixel using the method ptr.
unsigned char * p = foo.ptr(y, x); // Y first, X after
p[0] = 0; // B
p[1] = 0; // G
p[2] = 255; // R