i need some help with haar transformation, i have to apply it on an image.
My math is bad, my english not all that awesome and i find it hard to understand from articles on the internet. I found this page http://www.cs.ucf.edu/~mali/haar/haar.cpp where the haar transformation is applied on 2d matrix. I suppose if i give image pixels matrix in there, it should work?
im confused about this stuff, could someone enlighten me a bit please?
Thank you!
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef struct {
unsigned char red,green,blue;
} PPMPixel;
typedef struct {
int x, y;
PPMPixel *data;
} PPMImage;
#define CREATOR "SUDIPTAARNAB"
#define RGB_COMPONENT_COLOR 255
static PPMImage *readPPM(const char *filename)
{
char buff[16];
PPMImage *img;
FILE *fp;
int c, rgb_comp_color;
//open PPM file for reading
fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
}
//read image format
if (!fgets(buff, sizeof(buff), fp)) {
perror(filename);
exit(1);
}
//check the image format
if (buff[0] != 'P' || buff[1] != '6') {
fprintf(stderr, "Invalid image format (must be 'P6')\n");
exit(1);
}
//alloc memory form image
img = (PPMImage *)malloc(sizeof(PPMImage));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
//check for comments
c = getc(fp);
while (c == '#') {
while (getc(fp) != '\n') ;
c = getc(fp);
}
ungetc(c, fp);
//read image size information
if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);
}
//read rgb component
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}
//check rgb component depth
if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
exit(1);
}
while (fgetc(fp) != '\n') ;
//memory allocation for pixel data
img->data = (PPMPixel*)malloc(img->x * img->y * sizeof(PPMPixel));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
//read pixel data from file
if (fread(img->data, 3 * img->x, img->y, fp) != img->y) {
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);
}
fclose(fp);
return img;
}
void writePPM(const char *filename, PPMImage *img)
{
FILE *fp;
//open file for output
fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
}
//write the header file
//image format
fprintf(fp, "P6\n");
//comments
fprintf(fp, "# Created by %s\n",CREATOR);
//image size
fprintf(fp, "%d %d\n",img->x,img->y);
// rgb component depth
fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);
// pixel data
fwrite(img->data, 3 * img->x, img->y, fp);
fclose(fp);
}
void imageDivide(const char *filename,PPMImage *img)
{
FILE *fp = fopen(filename,"rb");
FILE *filePtr;
filePtr = fopen ("floatArray.txt","w");
int width = 288;
int height = 352;
int i,j,m,k,l,i1,j1,l1,n1;
int *sum;
float *mean,*var;
unsigned char buff[(288*352)];
unsigned char image[288][352];
size_t n = fread( buff, sizeof(buff[0]), sizeof(buff), fp );
fclose(fp);
for(i =0; i < height; i++)
{
for(j = 0; j < width;j++)
{
image[j][i] = buff[(i*width)+j];
}
}
unsigned char dividedimage[(288*352)/(8*8)][8][8];
mean=(float *)malloc(sizeof(float)*1584);
var=(float *)malloc(sizeof(float)*1584);
sum=(int *)malloc(sizeof(int)*1584);
for(i = 0; i < height/8; i++)
{
for(j = 0; j < width/8;j++)
{
for(k = i*8, l = 0; k < (i*8)+8; k++,l++)
{
for(m = j*8, n = 0; m < (j*8)+8; m++,n++)
{
dividedimage[(i*(width/8))][n][l] = image[m][k];
}
}
}
}
printf("\n no of grids::%d i=%d j=%d,k=%d,m=%d n=%d",(i*(width/8)),i,j,k,m,n);
for(i1=0;i1<(i*(width/8));i1++)
{
sum[i1]=0;
printf("\nprinting info of %dth grid::\n",i1+1);
for(n1=0;n1<n;n1++)
{
for(l1=0;l1<n;l1++)
{
// printf("%5d",dividedimage[i1][j1][l1]);
sum[i1]=sum[i1]+(int)dividedimage[i1][j1][l1];
}
printf("\n");
}
mean[i1]=sum[i1]/64;
// printf("\n sum of intensities of grid %d is ::%d and mean is %f\n",i1+1,sum[i1],mean[i1]);
//printf()
}
for(i1=0;i1<(i*(width/8));i1++)
{
var[i1]=0;
printf("\nprinting info of %dth grid::\n",i1+1);
for(n1=0;n1<n;n1++)
{
for(l1=0;l1<n;l1++)
{
printf("%5d",dividedimage[i1][j1][l1]);
//sum[i1]=sum[i1]+(int)dividedimage[i1][j1][l1];
var[i1]=var[i1]+pow(((int)dividedimage[i1][j1][l1]-mean[i1]),2);
}
printf("\n");
}
var[i1]=var[i1]/64;
printf("\n variance of grid %d is ::%f\n",i1+1,var[i1]);
}
//printf()
for (i = 0; i < 1584; i++) {
// y[i] = var[i1]);
printf("\n%f",var[i]);
fprintf (filePtr, "%5f\n", var[i]);
}
haar1d(var,1584);
}
/** The 1D Haar Transform **/
void haar1d(float *vec, int n)
{
int i=0;
int w=n;
FILE *filePtr;
filePtr = fopen ("1dhaarwavelet.txt","w");
float *vecp ;
vecp=(float *)malloc(sizeof(float)*n);
for(i=0;i<n;i++)
vecp[i] = 0;
while(w>1)
{
w/=2;
for(i=0;i<w;i++)
{
vecp[i] = (vec[2*i] + vec[2*i+1])/sqrt(2.0);
vecp[i+w] = (vec[2*i] - vec[2*i+1])/sqrt(2.0);
}
for(i=0;i<(w*2);i++)
vec[i] = vecp[i];
}
// delete [] vecp;
printf("\nthe 1d haarwavelet trasform is::");
for (i = 0; i < n; i++) {
printf("\n%f",vec[i]);
fprintf (filePtr, "%5f\n", vec[i]);
}
}
/** A Modified version of 1D Haar Transform, used by the 2D Haar Transform function **/
void haar1(float *vec, int n, int w)
{
int i=0;
float *vecp = (float *)malloc(sizeof(float)*n);
for(i=0;i<n;i++)
vecp[i] = 0;
w/=2;
for(i=0;i<w;i++)
{
vecp[i] = (vec[2*i] + vec[2*i+1])/sqrt(2.0);
vecp[i+w] = (vec[2*i] - vec[2*i+1])/sqrt(2.0);
}
for(i=0;i<(w*2);i++)
vec[i] = vecp[i];
// delete [] vecp;
}
/** The 2D Haar Transform **/
void haar2(float **matrix, int rows, int cols)
{
float *temp_row = (float *)malloc(sizeof(float)*cols);
float *temp_col = (float *)malloc(sizeof(float)*rows);
int i=0,j=0;
int w = cols, h=rows;
while(w>1 || h>1)
{
if(w>1)
{
for(i=0;i<h;i++)
{
for(j=0;j<cols;j++)
temp_row[j] = matrix[i][j];
haar1(temp_row,cols,w);
for(j=0;j<cols;j++)
matrix[i][j] = temp_row[j];
}
}
if(h>1)
{
for(i=0;i<w;i++)
{
for(j=0;j<rows;j++)
temp_col[j] = matrix[j][i];
haar1(temp_col, rows, h);
for(j=0;j<rows;j++)
matrix[j][i] = temp_col[j];
}
}
if(w>1)
w/=2;
if(h>1)
h/=2;
}
// delete [] temp_row;
// delete [] temp_col;
}
int main(){
char filein[100],fileout[100];
PPMImage *image1,*image2;
int m,i,j;
printf("\nEnter the input file name::");
gets(filein);
image1 = readPPM(filein);
imageDivide(filein,image1);
// printf("\nEnter the output file name::");
// gets(fileout);
// writePPM(fileout,image1);
float **mat = (float **)malloc(sizeof(float*)*4);
for(m=0;m<4;m++)
mat[m] = (float *)malloc(sizeof(float)*4);
mat[0][0] = 5; mat[0][1] = 6; mat[0][2] = 1; mat[0][3] = 2;
mat[1][0] = 4; mat[1][1] = 2; mat[1][2] = 5; mat[1][3] = 5;
mat[2][0] = 3; mat[2][1] = 1; mat[2][2] = 7; mat[2][3] = 1;
mat[3][0] = 6; mat[3][1] = 3; mat[3][2] = 5; mat[3][3] = 1;
haar2(mat,4,4);
printf("\nafter 2d haarwavelet::\n");
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
printf(" %f ",mat[i][j]);
}
printf("\n");
}
printf("Press any key...");
getchar();
}
If you're trying to do object detection using Haar features, pay a look at OpenCV:
http://opencv.willowgarage.com/documentation/cpp/object_detection.html
There is an example at the end of the URL you point to.
Look inside the main() function.
the 2D variant takes a float** and two parameters, height and width
the float** points to rows of grayscale pixels
each row is a float*, a pointer to the first pixel in the row
each float value is the intensity value of the pixel
in the example code, the dimensions are 4x4.
This is where the memory is allocated:
float **mat = new float*[4];
for(int m=0;m<4;m++)
mat[m] = new float[4];
This is where the pixel values are set:
mat[0][0] = 5; mat[0][1] = 6; mat[0][2] = 1; mat[0][3] = 2;
mat[1][0] = 4; mat[1][1] = 2; mat[1][2] = 5; mat[1][3] = 5;
mat[2][0] = 3; mat[2][1] = 1; mat[2][2] = 7; mat[2][3] = 1;
mat[3][0] = 6; mat[3][1] = 3; mat[3][2] = 5; mat[3][3] = 1;
This is where the haar2 function is called:
haar2(mat,4,4);
All you need to do is provide the data as needed by the function (float**) with the right dimensions. You probably want to store the results to an output file that you can open in an image viewing application.
Look for the PGM format for a really easy solution. Note that the results of the haar function will give you floating point values, which you may have to compress down to 8 bit to view the image.
Related
Although I have successfully utilized stb_image/CImg/lodepng open source to get a char array, the memory usage is too huge that I can't implement it in a low power embedded system.
Therefore, I try to use libpng to read a png type image, and get a char array.
However, I am completely not familiar with libpng......
Anyone can help?
According to some website sample programs, I write the following function. But I encounter Segmentation Fault, I think that I have problem dealing with the variables, raw_pointers and image. Anyone can review my code and give me some suggestions?
unsigned char* read_png_file(const char *filename)
{
FILE *fp = fopen(filename, "rb");
int bit_depth;
int color_type;
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info = png_create_info_struct(png);
png_init_io(png, fp);
png_read_info(png, info);
width = png_get_image_width(png, info);
height = png_get_image_height(png, info);
color_type = png_get_color_type(png, info);
bit_depth = png_get_bit_depth(png, info);
int numchan = 4;
// Set up row pointers
row_pointers = (unsigned char**) malloc(sizeof(unsigned char) * height);
for (int y=0; y<height; y++)
row_pointers[y] = (unsigned char*) malloc(sizeof(unsigned char) * width);
png_read_image(png, row_pointers);
// Put row pointers data into image
unsigned char * image = (unsigned char *) malloc (numchan*width*height);
for (unsigned int i=0;i<height;i++)
for (unsigned int j=0;j<width;i++)
*image++ = row_pointers[j][i];
fclose(fp);
cout << height << ", " << width << ", " << bit_depth << ", " << numchan << endl;
return image;
}
I successfully use libpng to get a char array.
However, the memory usage is up to 915.1KB which is higher than stb_image !!! (Use Valgrind)
Ah... Could anyone tell me some directions to optimize the memory usage?
unsigned char* read_png_file(const char *filename)
{
FILE *fp = fopen(filename, "rb");
png_byte bit_depth;
png_byte color_type;
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info = png_create_info_struct(png);
png_init_io(png, fp);
png_read_info(png, info);
width = png_get_image_width(png, info);
height = png_get_image_height(png, info);
color_type = png_get_color_type(png, info);
bit_depth = png_get_bit_depth(png, info);
if(color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png);
if(png_get_valid(png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);
if(color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
png_read_update_info(png, info);
int numchan = 4;
// Set up row pointer
png_bytep *row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
unsigned int i, j;
for (i = 0; i < height; i++)
row_pointers[i] = (png_bytep)malloc(png_get_rowbytes(png,info));
png_read_image(png, row_pointers);
// Put row pointers data into image
unsigned char *image = (unsigned char *) malloc (numchan*width*height);
int count = 0;
for (i = 0 ; i < height ; i++)
{
for (j = 0 ; j < numchan*width ; j++)
{
image[count] = row_pointers[i][j];
count += 1;
}
}
fclose(fp);
for (i = 0; i < height; i++)
free(row_pointers[i]) ;
free(row_pointers) ;
return image;
}
I am using a lookup table to convert raw pixel data between color spaces and coding variants. This is the definition of my LUT:
typedef struct
{
unsigned char data[3];
} rgb;
rgb LUTYUVTORGB[256][256][256];
It is initialized like this:
// loop through all possible values
for (int in_1 = 0; in_1 < 256; in_1++) {
for (int in_2 = 0; in_2 < 256; in_2++) {
for (int in_3 = 0; in_3 < 256; in_3++) {
int out_1, out_2, out_3;
// LUT YUV -> RGB
// convert to rgb (http://softpixel.com/~cwright/programming/colorspace/yuv/)
out_1 = (int)(in_1 + 1.4075 * (in_3 - 128));
out_2 = (int)(in_1 - 0.3455 * (in_2 - 128) - (0.7169 * (in_3 - 128)));
out_3 = (int)(in_1 + 1.7790 * (in_2 - 128));
// clamp values
if (out_1 < 0) { out_1 = 0; } else if (out_1 > 255) { out_1 = 255; }
if (out_2 < 0) { out_2 = 0; } else if (out_2 > 255) { out_2 = 255; }
if (out_3 < 0) { out_3 = 0; } else if (out_3 > 255) { out_3 = 255; }
// set values in LUT
LUTYUVTORGB[in_1][in_2][in_3].data[0] = (unsigned char)out_1;
LUTYUVTORGB[in_1][in_2][in_3].data[1] = (unsigned char)out_2;
LUTYUVTORGB[in_1][in_2][in_3].data[2] = (unsigned char)out_3;
}
}
}
The LUT is then applied to copy the raw pixel data to a QImage():
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
xpos = (y*w + x); // don't calculate 3 times
buff[x * 3 + 0] = psImage->comps[0].data[xpos];
buff[x * 3 + 1] = psImage->comps[1].data[xpos];
buff[x * 3 + 2] = psImage->comps[2].data[xpos];
}
memcpy(image.scanLine(y), buff, bytes_per_line);
}
The values of the LUT are static, and have to be initialized every time the programm starts. Is there any way to initialize it via the preprocessor? Or would it be recommendable to save it in a file?
EDIT: The conversion is used in a time critical video application where every frame has to be processed individually.
Thanks very much in advance!
I have created one dimensional array for this table, it is convenient to save and load such array. I think using this array in runtime wont decrease performance. But I didn't test it for performance differences.
#include <stdio.h>
#include <stdlib.h>
#define LUTSIZE 0x1000000
typedef struct
{
unsigned char data[3];
} rgb;
rgb *LUT;
inline int LUT_index(int in_1, int in_2, int in_3) {
return in_1 * 0x10000 + in_2 * 0x100 + in_3 * 0x1;
}
inline rgb LUT_value(int in_1, int in_2, int in_3) {
return LUT[LUT_index(in_1,in_2,in_3)];
}
void save(rgb *LUT, char* fileName) {
FILE* file = fopen(fileName,"wb");
int index;
for (int in_1 = 0; in_1 < 256; in_1++) {
for (int in_2 = 0; in_2 < 256; in_2++) {
for (int in_3 = 0; in_3 < 256; in_3++) {
int out_1, out_2, out_3;
// LUT YUV -> RGB
// convert to rgb (http://softpixel.com/~cwright/programming/colorspace/yuv/)
out_1 = (int)(in_1 + 1.4075 * (in_3 - 128));
out_2 = (int)(in_1 - 0.3455 * (in_2 - 128) - (0.7169 * (in_3 - 128)));
out_3 = (int)(in_1 + 1.7790 * (in_2 - 128));
// clamp values
if (out_1 < 0) { out_1 = 0; } else if (out_1 > 255) { out_1 = 255; }
if (out_2 < 0) { out_2 = 0; } else if (out_2 > 255) { out_2 = 255; }
if (out_3 < 0) { out_3 = 0; } else if (out_3 > 255) { out_3 = 255; }
index = LUT_index(in_1,in_2,in_3);
// set values in LUT
LUT[index].data[0] = (unsigned char)out_1;
LUT[index].data[1] = (unsigned char)out_2;
LUT[index].data[2] = (unsigned char)out_3;
}
}
}
fwrite((void*)LUT, sizeof(rgb),LUTSIZE,file);
fclose(file);
}
void read(rgb *LUT, char* fileName) {
FILE* file = fopen(fileName, "rb");
fread((void*)LUT,sizeof(rgb),LUTSIZE,file);
fclose(file);
}
int main(int argc, char *argv[])
{
LUT = (rgb*)malloc(LUTSIZE * sizeof(rgb));
save(LUT, "LUT_data");
rgb testValue = LUT_value(5,3,7);
printf("%d %d %d\n", testValue.data[0], testValue.data[1], testValue.data[2]);
read(LUT, "LUT_data");
testValue = LUT_value(5,3,7);
printf("%d %d %d\n", testValue.data[0], testValue.data[1], testValue.data[2]);
free(LUT);
}
I'm creating a qrcode with the library qrencode.h
This creation is working nice but how would one output the qrcode to a BMP file within c++?
At this very moment i have this code:
const char* szSourceSring = QRCODE_TEXT;
unsigned int unWidth, x, y, l, n, unWidthAdjusted, unDataBytes;
unsigned char* pRGBData, *pSourceData, *pDestData;
QRcode* pQRC;
FILE* f;
if (pQRC = QRcode_encodeString(szSourceSring, 4, QR_ECLEVEL_H, QR_MODE_8, 1))
{
unWidth = pQRC->width;
unWidthAdjusted = unWidth * OUT_FILE_PIXEL_PRESCALER * 3;
if (unWidthAdjusted % 4)
unWidthAdjusted = (unWidthAdjusted / 4 + 1) * 4;
unDataBytes = unWidthAdjusted * unWidth * OUT_FILE_PIXEL_PRESCALER;
// Allocate pixels buffer
if (!(pRGBData = (unsigned char*)malloc(unDataBytes)))
{
printf("Out of memory");
}
// Preset to white
memset(pRGBData, 0xff, unDataBytes);
// Prepare bmp headers
BITMAPFILEHEADER kFileHeader;
kFileHeader.bfType = 0x4D42; // "BM"
kFileHeader.bfSize = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
unDataBytes;
kFileHeader.bfReserved1 = 0;
kFileHeader.bfReserved2 = 0;
kFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER kInfoHeader;
kInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
kInfoHeader.biWidth = unWidth * OUT_FILE_PIXEL_PRESCALER;
kInfoHeader.biHeight = -((int)unWidth * OUT_FILE_PIXEL_PRESCALER);
kInfoHeader.biPlanes = 1;
kInfoHeader.biBitCount = 24;
kInfoHeader.biCompression = BI_RGB;
kInfoHeader.biSizeImage = 0;
kInfoHeader.biXPelsPerMeter = 0;
kInfoHeader.biYPelsPerMeter = 0;
kInfoHeader.biClrUsed = 0;
kInfoHeader.biClrImportant = 0;
// Convert QrCode bits to bmp pixels
pSourceData = pQRC->data;
for(y = 0; y < unWidth; y++)
{
pDestData = pRGBData + unWidthAdjusted * y * OUT_FILE_PIXEL_PRESCALER;
for(x = 0; x < unWidth; x++)
{
if (*pSourceData & 1)
{
for(l = 0; l < OUT_FILE_PIXEL_PRESCALER; l++)
{
for(n = 0; n < OUT_FILE_PIXEL_PRESCALER; n++)
{
*(pDestData + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_B;
*(pDestData + 1 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_G;
*(pDestData + 2 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_R;
}
}
}
pDestData += 3 * OUT_FILE_PIXEL_PRESCALER;
pSourceData++;
}
}
// Output the bmp file
/*if (((f = fopen(OUT_FILE, "r")) != NULL))
{*/
f = fopen(OUT_FILE, "wb");
fwrite(&kFileHeader, sizeof(BITMAPFILEHEADER), 14, f);
fwrite(&kInfoHeader, sizeof(BITMAPINFOHEADER), 40, f);
fwrite(pRGBData, sizeof(unsigned char), unDataBytes, f);
fclose(f);
/* }
else
{
printf("Unable to open file");
}
*/
// Free data
free(pRGBData);
QRcode_free(pQRC);
}
else
{
printf("NULL returned");
}
But somehow this creates a BMP with corrupt headers. Whenever i'm opening the bmp file it says:
"BMP Image has unsupported header size"
What am i doing wrong?
And is it possible to save to png instead of BMP?
I have access to the libPNG library
Here is a code example which dumps a 24 bpp bmp file created from a QR-Code. The error you see is probably not caused by the QR-Code library, but rather something in the bmp file code.
The bmp file created by this example works fine with the image viewer packaged with my Windows 8.1. If you also do not see the error, you could check for differences in each binary output to pinpoint the problem. If you want.
This question is tagged "C++" and "C++11", so this example uses the C++ std library for file output, and doesn't use malloc. (But almost equally bad -- I use new and delete in some container code, where a std::vector member is preferred...don't tell anyone). Also, this example writes each piece of data directly to the file, instead of using a file-sized intermediate buffer, like pDestData.
#include <iostream>
#include <fstream>
// A fake (or "somewhat limited") QR Code data container
struct Qrc {
int dimsize; // the width and height
unsigned char* data; // buffer which contains the elements
Qrc() {
static const unsigned int bin[] = { // encodes an important secret message
0xfc8b7d7f,0xa801a83,0xd6e54d76,0xaa9eb2ed,0x43ed05db,0xb8786837,0x55555fe0,
0x5a4c807f,0xcf315c00,0x6e8019ce,0xc7819e0d,0xd4857ba8,0x4ac5e347,0xf6f349ba,
0xd433ccdd,0x2998361e,0x4453fab3,0x526d9085,0x81f38924,0xb4da0811,0x84b3131a,
0x9639915e,0x3b74a4ff,0x42aa0c11,0x4127be16,0x1f4350,0xff620296,0xad54de1,
0xd38c2272,0xa3f76155,0x5366a7ab,0x9bdd2257,0x300d5520,0x85842e7f,0 };
dimsize = 33;
data = new unsigned char[dimsize * dimsize];
auto p = data;
auto endp = p + dimsize * dimsize;
for(unsigned int b : bin) {
for(int i=0; i<32; ++i) {
if(p == endp) break;
*(p++) = b & (1 << i) ? 255 : 0;
} } }
Qrc(const Qrc&) = delete;
Qrc& operator = (const Qrc&) = delete;
~Qrc() { delete [] data; }
};
struct BIH { // a private definition of BITMAPINFOHEADER
unsigned int sz;
int width, height;
unsigned short planes;
short bits;
unsigned int compress, szimage;
int xppm, yppm;
unsigned int clrused, clrimp;
};
void SaveBmp(const char* filename, const Qrc& qrc) {
// Asker's Qrc struct delivered as a pointer, from a C API, but this example doesn't mimic that.
std::ofstream ofs(filename, std::ios_base::out | std::ios_base::binary);
if(!ofs) {
std::cout << "Writing " << filename << " failed\n";
return;
}
const int side_len = qrc.dimsize; // width and height of the (square) QR Code
const int pixel_side_len = 4; // QRC element's size in the bmp image (in pixels)
const int bmp_line_bytes = side_len * pixel_side_len * 3;
const int bmp_line_pad_bytes = (4 - bmp_line_bytes % 4) % 4; // bmp line data padding size
const int bmp_data_size = side_len * (bmp_line_bytes + bmp_line_pad_bytes);
BIH bih = { sizeof(bih) };
bih.width = side_len * pixel_side_len; // element count * element size
bih.height = -side_len * pixel_side_len; // negative height => data begins at top of image
bih.planes = 1;
bih.bits = 24;
const int header_size = sizeof(bih) + 14; // size of the bmp file header
const int filesize = header_size + bmp_data_size; // size of the whole file
ofs.write("BM", 2);
ofs.write(reinterpret_cast<const char*>(&filesize), 4);
ofs.write("\0\0\0\0", 4); // 2x 16-bit reserved fields
ofs.write(reinterpret_cast<const char*>(&header_size), 4);
ofs.write(reinterpret_cast<const char*>(&bih), sizeof(bih));
// pixel colors, as Blue, Green, Red char-valued triples
// the terminating null also makes these usable as 32bpp BGRA values, with Alpha always 0.
static const char fg_color[] = "\0\0\0";
static const char bg_color[] = "\xff\xff\xff";
auto pd = qrc.data;
// send pixel data directly to the bmp file
// QRC elements are expanded into squares
// whose sides are "pixel_side_len" in length.
for(int y=0; y<side_len; ++y) {
for(int j=0; j<pixel_side_len; ++j) {
auto pdj = pd;
for(int x=0; x<side_len; ++x) {
for(int i=0; i<pixel_side_len; ++i) {
// *pdj will be 0 or 255 (from "fake" Qrc)
// Using "*pdj & 1" here, just to match asker's code
// without knowing why this was done.
ofs.write(*pdj & 1 ? fg_color : bg_color, 3);
}
++pdj;
}
if(bmp_line_pad_bytes) {
ofs.write("\0\0\0", bmp_line_pad_bytes);
}
}
pd += side_len;
}
}
int main() {
SaveBmp("MyQrCode.bmp", Qrc());
}
I am currently working on imaging processing using arrays to store R,G,B values from a 24 bit BITMAP image of width 120 and height 100 pixels.
Visual Studio 2010 is being used.
I have currently extracted the individual R,G,B values into three separate2D arrays from the 24 bit bitmap (it is assumed correct as the correct R,G,B values have been written to a text file with the right pixel count as well).
These individual R,G,B values need to be restored back into an array (either 1D or 2D), which is then written to an image file. The output should be identical to the original image.
I have tried the following but the output is currently incorrect (same width, height and memory size but colouring is incorrect).
Appreciate your guidance and feedback.
#include <iostream>
#include <fstream>
#include <windows.h>
#include <WinGDI.h>
unsigned char** Allocate2DArray(int w, int h)
{
unsigned char ** buffer = new unsigned char * [h]; // allocate the rows
unsigned char * memory_pool = new unsigned char [w*h]; // allocate memory pool
for (int i = 0; i < h; ++i)
{
buffer[i] = memory_pool; // point row pointer
memory_pool += w; // go to next row in memory pool
}
return buffer;
}
void DeAllocate2DArray(unsigned char** buffer)
{
delete [] buffer[0]; // delete the memory pool
delete [] buffer; // delete the row pointers
}
using namespace std;
int main()
{
const int width = 120;
const int height = 100;
int bytesPerPixel = 3;
unsigned char m_cHeaderData[54];
unsigned char** m_cImageData = new unsigned char* [height];
for( int i = 0; i <height; i++)
{
m_cImageData[i] = new unsigned char [width*bytesPerPixel];
}
ifstream* m_pInFile;
m_pInFile = new ifstream;
m_pInFile->open("image.bmp", ios::in | ios::binary);
m_pInFile->seekg(0, ios::beg);
m_pInFile->read(reinterpret_cast<char*>(m_cHeaderData), 54);
for(int i = 0; i <height; i++)
{
m_pInFile->read(reinterpret_cast<char*>(m_cImageData[i]), width*bytesPerPixel);
}
m_pInFile->close();
// Declare a pointer of the type you want.
// This will point to the 1D array
unsigned char* array_1D;
array_1D = new unsigned char[height*width*bytesPerPixel];
if(array_1D == NULL) return 0; // return if memory not allocated
// Copy contents from the existing 2D array
int offset = 0;
for(int j=0; j<height; j++) // traverse height (or rows)
{
offset = width * bytesPerPixel* j;
for(int i=0; i<width*bytesPerPixel; i++) // traverse width
{
array_1D[offset + i] = m_cImageData[j][i];
// update value at current (i, j)
}
}
// Declare three 2D arrays to store R,G, and B planes of image.
unsigned char**arrayR_2D, **arrayG_2D, **arrayB_2D;
arrayR_2D = Allocate2DArray(width, height);
arrayG_2D = Allocate2DArray(width, height);
arrayB_2D = Allocate2DArray(width, height);
// return if memory not allocated
if(arrayR_2D == NULL || arrayG_2D == NULL || arrayB_2D == NULL) return 0;
// Extract R,G,B planes from the existing composite 1D array
ofstream RGBdata2D;
RGBdata2D.open("RGBdata2D.txt");
int pixelCount = 0;
int offsetx = 0;
int counter = 0;
for(int j=0; j<height; j++) // traverse height (or rows)
{
offsetx = width * j * bytesPerPixel;
for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width
{
arrayB_2D[j][counter] = array_1D[offsetx + i+0];
arrayG_2D[j][counter] = array_1D[offsetx + i+1];
arrayR_2D[j][counter] = array_1D[offsetx + i+2];
RGBdata2D<<"B: "<< (int)arrayB_2D[j][counter] << " G: " << (int)arrayG_2D[j][counter] << " R: " << (int)arrayR_2D[j][counter]<< endl;
pixelCount++;
++counter;
}
counter = 0;
}
RGBdata2D<<"count of pixels: "<< pixelCount << endl;
RGBdata2D.close();
//put RGB from 2D array contents back into a 1D array
offset = 0;
counter = 0;
for(int j=0; j<height; j++) // traverse height (or rows)
{
offset = width * bytesPerPixel * j;
for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width
{
array_1D[offset + i+0] = arrayB_2D[j][counter++];
array_1D[offset + i+1] = arrayG_2D[j][counter++];
array_1D[offset + i+2] = arrayR_2D[j][counter++];
}
counter = 0;
}
ofstream* m_pOutFileRGB;
m_pOutFileRGB = new ofstream;
m_pOutFileRGB->open("imageCopyRGB.bmp", ios::out | ios::trunc | ios::binary);
m_pOutFileRGB->write(reinterpret_cast<char*>(m_cHeaderData), 54);
for(int i = 0; i <height; i++)
{
m_pOutFileRGB->write(reinterpret_cast<char*>(array_1D), width*bytesPerPixel);
}
m_pOutFileRGB->close();
// After complete usage, delete the memory dynamically allocated
DeAllocate2DArray(arrayR_2D);
DeAllocate2DArray(arrayG_2D);
DeAllocate2DArray(arrayB_2D);
// After complete usage, delete the memory dynamically allocated
delete[] array_1D; //delete the pointer to pointer
for(int i = 0; i <height; i++)
{
delete[] m_cImageData[i];
}
delete[] m_cImageData;
system("pause");
return 0;
}
I didn't test by myself, but at this point
for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width
{
array_1D[offset + i+0] = arrayB_2D[j][counter++];
array_1D[offset + i+1] = arrayG_2D[j][counter++];
array_1D[offset + i+2] = arrayR_2D[j][counter++];
}
You inclement counter too many times, and it may lead to incorrect result.
Instead, try this:
for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width
{
array_1D[offset + i+0] = arrayB_2D[j][counter];
array_1D[offset + i+1] = arrayG_2D[j][counter];
array_1D[offset + i+2] = arrayR_2D[j][counter];
counter++;
}
My taks is to restore an mp3 file, wich is coded bit-per-bit in a PNG file. I got the right bits from the PNG RGB data (per pixel) in a vector. I'm using C++.
I have to go through the png file and read the RGB data of a pixel: then I have 3 decimal values. From binary representation of the decimal values, I need the least smallest local value. The 11 pixels shows on 33 bits the length of the mp3. Then i decode all of the binary data from the pixels, and put in a vector;
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <vector>
#include <math.h>
#include <iostream>
#include <fstream>
#define PNG_DEBUG 3
#include <png.h>
void abort_(const char * s, ...)
{
va_list args;
va_start(args, s);
vfprintf(stderr, s, args);
fprintf(stderr, "\n");
va_end(args);
abort();
}
void itob(short n, std::vector<int> &bin)
{
int d = n;
if (n > 1)
{
d = n % 2;
itob(n / 2, bin);
}
bin.push_back(d);
}
void btoi(unsigned int& n, std::vector<int> bin)
{
n = 0;
int k = 32;
for(int i = 0; i < bin.size() ; i++){
if(bin[i] == 1){
long int num = pow(2,k);
n += num;
}
k--;
}
}
int x, y;
int width, height;
png_byte color_type;
png_byte bit_depth;
png_structp png_ptr;
png_infop info_ptr;
int number_of_passes;
png_bytep * row_pointers;
void read_png_file()
{
unsigned char header[8]; // 8 is the maximum size that can be checked
/* open file and test for it being a png */
FILE *fp = fopen("image.png", "rb");
if (!fp)
abort_("[read_png_file] File %s could not be opened for reading", "image.png");
fread(header, 1, 8, fp);
if (png_sig_cmp(header, 0, 8))
abort_("[read_png_file] File %s is not recognized as a PNG file", "image.png");
/* initialize stuff */
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
abort_("[read_png_file] png_create_read_struct failed");
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
abort_("[read_png_file] png_create_info_struct failed");
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
number_of_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
for (y=0; y<height; y++)
row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
png_read_image(png_ptr, row_pointers);
fclose(fp);
}
void process_file(void)
{
if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGBA)
abort_("[process_file] input file is PNG_COLOR_TYPE_RGB but must be PNG_COLOR_TYPE_RGB "
"(lacks the alpha channel)");
if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGB)
abort_("[process_file] color_type of input file must be PNG_COLOR_TYPE_RGB (%d) (is %d)",
PNG_COLOR_TYPE_RGBA, png_get_color_type(png_ptr, info_ptr));
printf("width: %d\nheight: %d\n", width, height);
int mHeader = 33; unsigned int mSize = 0;
std::vector<int> mSizeByBites;
for (y=0; y<height; y++) {
png_byte* row = row_pointers[y];
for (x=0; x<width; x++) {
png_byte* ptr = &(row[x*3]);
if(mHeader == 0){ break; }
mHeader-=3;
std::vector<int> b;
itob(ptr[0], b);
mSizeByBites.push_back(b[b.size()-1]);
b.clear();
itob(ptr[1], b);
mSizeByBites.push_back(b[b.size()-1]);
b.clear();
itob(ptr[2], b);
mSizeByBites.push_back(b[b.size()-1]);
b.clear();
}
if(mHeader == 0){ break; }
}
for(int i =0; i<mSizeByBites.size(); i++){
printf("%d", mSizeByBites[i]);
}
btoi(mSize, mSizeByBites);
printf(" = %i\n", mSize);
std::vector<int> mDataBaBites;
for (y=0; y<height; y++) {
png_byte* row = row_pointers[y];
for (x=0; x<width; x++) {
if(mSize <= 0){ break; }
png_byte* ptr = &(row[x*3]);
std::vector<int> b;
itob(ptr[0], b);
mDataBaBites.push_back(b[b.size()-1]);
b.clear();
mSize--;
if(mSize <= 0){ break; }
itob(ptr[1], b);
mDataBaBites.push_back(b[b.size()-1]);
b.clear();
mSize--;
if(mSize <= 0){ break; }
itob(ptr[2], b);
mDataBaBites.push_back(b[b.size()-1]);
b.clear();
mSize--;
if(mSize <= 0){ break; }
printf("%i\n", mSize);
}
if(mSize<=0){ break; }
}
std::ofstream output("result.mp3", std::ios::out | std::ios::binary);
printf("[D] Writing to file start: %li\n", mDataBaBites.size());
output.write( (char*)(&mDataBaBites[0]), mDataBaBites.size() );
output.close();
}
int main(int argc, char **argv)
{
read_png_file();
process_file();
return 0;
}
Now I have no clue, how to write it in a file, wich i can play as an mp3. I tried to convert the bits to hexa.
What is the correct format of an mp3 file? How can I write the bits in the correct format?
Try this:
#include <fstream> //For std::min
std::ofstream mp3File( "restored.mp3", std::ios::out | std::ios::binary );
//Assuming rgbData is a char* with the mp3 data,
//and rgbDataSize is its size in bytes
mp3File.write( rgbData, rgbDataSize );
mp3File.close();
Update: When we (programmers) say "binary representation" we almost always mean bytes, not bits. From your description of the decoding process, I gather you should compare the 3 RGB components for each pixel and keep the minimum as the decoded byte. To do that:
#include <algorithm>
//...
std::vector<char> mDataBaBites;
for (y=0; y<height; y++) {
png_byte* row = row_pointers[y];
for (x=0; x<width; x++) {
png_byte red = row[x*3];
png_byte green = row[x*3 + 1];
png_byte blue = row[x*3 + 2];
png_byte minByte = std::min( std::min(red,green), blue );
mDataBaBites.push_back( minByte );
mSize -= 3;
}
if(mSize<=0){ break; }
}
std::ofstream output("result.mp3", std::ios::out | std::ios::binary);
printf("[D] Writing to file start: %li\n", mDataBaBites.size());
output.write( (char*)(&mDataBaBites[0]), mDataBaBites.size() );
output.close();
Update 2:
std::ofstream output("result.mp3", std::ios::out | std::ios::binary);
printf("[D] Writing to file start: %li\n", mDataBaBites.size());
for( int i=0; i<mDataBaBites.size(); i+=8 ){
char decodedByte = 0;
for( int j=0; j<8; j++ )
decodedByte |= (mDataBaBites[i+j] << j);
output.write( (char*)(&mDataBaBites[0]), 1 );
}
output.close();
If this doesn't work either, you might want to clarify the decoding process definition (which is its source? is there some formal definition?)