C++ create png/bitmap from array of numbers - c++

So i found this link regarding my question, but it is for c#
Create a PNG from an array of bytes
I have a variable int array of numbers.
i will call it "pix[ ]"
for now it can be any size from 3 to 256, later possibly bigger.
What i want to do now, is to convert it into a pixel image.
I am still a noobin c++ so pleas excuse me.
I tried to download some libaries that make working with libpng easier, but they do not seem to be working (ubuntu, code::blocks)
So i have questions in the following:
1) how do you create a new bitmap (which libaries, which command)?
2) how do i fill it with information from "pix[ ]" ?
3) how do i save it?
if it is a repost of a question i am happy about a link also ;)
Here is what i worked out so far, thanks for your help.
int main(){
FILE *imageFile;
int x,y,pixel,height=2,width=3;
imageFile=fopen("image.pgm","wb");
if(imageFile==NULL){
perror("ERROR: Cannot open output file");
exit(EXIT_FAILURE);
}
fprintf(imageFile,"P3\n"); // P3 filetype
fprintf(imageFile,"%d %d\n",width,height); // dimensions
fprintf(imageFile,"255\n"); // Max pixel
int pix[100] {200,200,200, 100,100,100, 0,0,0, 255,0,0, 0,255,0, 0,0,255};
fwrite(pix,1,18,imageFile);
fclose(imageFile);
}
i have not fully understood what it does. i can open the output image, but it is not a correct representation of the Array.
If i change things around, for example making a 2 dimensional array, then the image viewer tells me "expected an integer" and doesn't show me an image.
So far so good.
As i have the array before the image i created a function aufrunden to round up to the next int number because i want to create a square image.
int aufrunden (double h)
{
int i =h;
if (h-i == 0)
{
return i;
}
else
{
i = h+1;
return i;
}
}
This function is used in the creation of the image.
If the image is bigger than the information the array provides like this (a is the length of th array)
double h;
h= sqrt(a/3.0);
int i = aufrunden(h);
FILE *imageFile;
int height=i,width=i;
It might happen now, that the array is a=24 long. aufrunden makes the image 3x3 so it has 27 values...meaning it is missing the values for 1 pixel.
Or worse it is only a=23 long. also creating a 3x3 image.
What will fwrite(pix,1,18,imageFile); write in those pixels for information? It would be best if the remaing values are just 0.
*edit never mind, i will just add 0 to the end of the array until it is filling up the whole square...sorry

Consider using a Netpbm format (pbm, pgm, or ppm).
These images are extremely simple text files that you can write without any special libraries. Then use some third-party software such as ImageMagick, GraphicsMagick, or pnmtopng to convert your image to PNG format. Here is a wiki article describing the Netpbm format.
Here's a simple PPM image:
P3 2 3 255
0 0 0 255 255 255
255 0 0 0 255 255
100 100 100 200 200 200
The first line contains "P3" (the "magic number identifying it as a text-PPM), 2 (width), 3 (height), 255 (maximum intensity).
The second line contains the two RGB pixels for the top row.
The third and fourth lines each contain the two RGB pixels for rows 2 and 3.
Use a larger number for maximum intensity (e.g. 1024) if you need a larger range of intensities, up to 65535.
Edited by Mark Setchell beyond this point - so I am the guilty party!
The image looks like this (when the six pixels are enlarged):
The ImageMagick command to convert, and enlarge, is like this:
convert image.ppm -scale 400x result.png
If ImageMagick is a bit heavyweight, or difficult to install you can more simply use the NetPBM tools (from here) like this (it's a single precompiled binary)
pnmtopng image.ppm > result.png

If, as it seems, you have got Magick++ and are happy to use that, you can write your code in C/C++ like this:
////////////////////////////////////////////////////////////////////////////////
// sample.cpp
// Mark Setchell
//
// ImageMagick Magick++ sample code
//
// Compile with:
// g++ sample.cpp -o sample $(Magick++-config --cppflags --cxxflags --ldflags --libs)
////////////////////////////////////////////////////////////////////////////////
#include <Magick++.h>
#include <iostream>
using namespace std;
using namespace Magick;
int main(int argc,char **argv)
{
unsigned char pix[]={200,200,200, 100,100,100, 0,0,0, 255,0,0, 0,255,0, 0,0,255};
// Initialise ImageMagick library
InitializeMagick(*argv);
// Create Image object and read in from pixel data above
Image image;
image.read(2,3,"RGB",CharPixel,pix);
// Write the image to a file - change extension if you want a GIF or JPEG
image.write("result.png");
}

You are not far off - well done for trying! As far as I can see, you only had a couple of mistakes:
You had P3 where you would actually need P6 if writing in binary.
You were using int type for your data, whereas you need to be using unsigned char for 8-bit data.
You had the width and height interchanged.
You were using the PGM extension which is for Portable Grey Maps, whereas your data is colour, so you need to use the PPM extension which is for Portable Pix Map.
So, the working code looks like this:
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *imageFile;
int x,y,pixel,height=3,width=2;
imageFile=fopen("image.ppm","wb");
if(imageFile==NULL){
perror("ERROR: Cannot open output file");
exit(EXIT_FAILURE);
}
fprintf(imageFile,"P6\n"); // P6 filetype
fprintf(imageFile,"%d %d\n",width,height); // dimensions
fprintf(imageFile,"255\n"); // Max pixel
unsigned char pix[]={200,200,200, 100,100,100, 0,0,0, 255,0,0, 0,255,0, 0,0,255};
fwrite(pix,1,18,imageFile);
fclose(imageFile);
}
If you then run that, you can convert the resulting image to a nice big PNG with
convert image.ppm -scale 400x result.png
If you subsequently need 16-bit data, you would change the 255 to 65535, and store in an unsigned short array rather than unsigned char and when you come to the fwrite(), you would need to write double the number of bytes.

The code below will take an integer array of pixel colors as input and write it to a .bmp bitmap file or, in reverse, read a .bmp bitmap file and store its image contents as an int array. It only requires the <fstream> library. The input parameter path can be for example C:/path/to/your/image.bmp and data is formatted as data[x+y*width]=(red<<16)|(green<<8)|blue;, whereby red, green and blue are integers in the range 0-255 and the pixel position is (x,y).
#include <string>
#include <fstream>
using namespace std;
typedef unsigned int uint;
int* read_bmp(const string path, uint& width, uint& height) {
ifstream file(path, ios::in|ios::binary);
if(file.fail()) println("\rError: File \""+filename+"\" does not exist!");
uint w=0, h=0;
char header[54];
file.read(header, 54);
for(uint i=0; i<4; i++) {
w |= (header[18+i]&255)<<(8*i);
h |= (header[22+i]&255)<<(8*i);
}
const int pad=(4-(3*w)%4)%4, imgsize=(3*w+pad)*h;
char* img = new char[imgsize];
file.read(img, imgsize);
file.close();
int* data = new int[w*h];
for(uint y=0; y<h; y++) {
for(uint x=0; x<w; x++) {
const int i = 3*x+y*(3*w+pad);
data[x+(h-1-y)*w] = (img[i]&255)|(img[i+1]&255)<<8|(img[i+2]&255)<<16;
}
}
delete[] img;
width = w;
height = h;
return data;
}
void write_bmp(const string path, const uint width, const uint height, const int* const data) {
const int pad=(4-(3*width)%4)%4, filesize=54+(3*width+pad)*height; // horizontal line must be a multiple of 4 bytes long, header is 54 bytes
char header[54] = { 'B','M', 0,0,0,0, 0,0,0,0, 54,0,0,0, 40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,24,0 };
for(uint i=0; i<4; i++) {
header[ 2+i] = (char)((filesize>>(8*i))&255);
header[18+i] = (char)((width >>(8*i))&255);
header[22+i] = (char)((height >>(8*i))&255);
}
char* img = new char[filesize];
for(uint i=0; i<54; i++) img[i] = header[i];
for(uint y=0; y<height; y++) {
for(uint x=0; x<width; x++) {
const int color = data[x+(height-1-y)*width];
const int i = 54+3*x+y*(3*width+pad);
img[i ] = (char)( color &255);
img[i+1] = (char)((color>> 8)&255);
img[i+2] = (char)((color>>16)&255);
}
for(uint p=0; p<pad; p++) img[54+(3*width+p)+y*(3*width+pad)] = 0;
}
ofstream file(path, ios::out|ios::binary);
file.write(img, filesize);
file.close();
delete[] img;
}
The code snippet was inspired by https://stackoverflow.com/a/47785639/9178992
For .png images, use lodepng.cpp and lodepng.h:
#include <string>
#include <vector>
#include <fstream>
#include "lodepng.h"
using namespace std;
typedef unsigned int uint;
int* read_png(const string path, uint& width, uint& height) {
vector<uchar> img;
lodepng::decode(img, width, height, path, LCT_RGB);
int* data = new int[width*height];
for(uint i=0; i<width*height; i++) {
data[i] = img[3*i]<<16|img[3*i+1]<<8|img[3*i+2];
}
return data;
}
void write_png(const string path, const uint width, const uint height, const int* const data) {
uchar* img = new uchar[3*width*height];
for(uint i=0; i<width*height; i++) {
const int color = data[i];
img[3*i ] = (color>>16)&255;
img[3*i+1] = (color>> 8)&255;
img[3*i+2] = color &255;
}
lodepng::encode(path, img, width, height, LCT_RGB);
delete[] img;
}

Related

How can I use openimageIO to store RGB values in arrays? (using C++, OpenGL)

I am using openimageIO to read and display an image from a JPG file, and I now need to store the RGB values in arrays so that I can manipulate and re-display them later.
I want to do something like this:
for (int i=0; i<picturesize;i++)
{
Rarray[i]=pixelredvalue;
Garray[i]=pixelgreenvalue;
Barray[i]=pixelbluevalue;
}
This is an openimageIO source that I found online: https://people.cs.clemson.edu/~dhouse/courses/404/papers/openimageio.pdf
"Section 3.2: Advanced Image Output" (pg 35) is the closest to what I'm doing, but I don't understand how I can use the channels to write pixel data to arrays. I also don't fully understand the difference between "writing" and "storing in an array". This is the piece of code in the reference that I am talking about:
int channels = 4;
ImageSpec spec (width, length, channels, TypeDesc::UINT8);
spec.channelnames.clear ();
spec.channelnames.push_back ("R");
spec.channelnames.push_back ("G");
spec.channelnames.push_back ("B");
spec.channelnames.push_back ("A");
I managed to read the image and display it using the code in the reference, but now I need to store all the pixel values in my array.
Here is another useful piece of code from the link, but again, I can't understand how to retrieve the individual RGB values and place them into an array:
#include <OpenImageIO/imageio.h>
OIIO_NAMESPACE_USING
...
const char *filename = "foo.jpg";
const int xres = 640, yres = 480;
const int channels = 3; // RGB
unsigned char pixels[xres*yres*channels];
ImageOutput *out = ImageOutput::create (filename);
if (! out)
return;
ImageSpec spec (xres, yres, channels, TypeDesc::UINT8);
out->open (filename, spec);
out->write_image (TypeDesc::UINT8, pixels);
out->close ();
ImageOutput::destroy (out);
But this is about writing to a file, and still does not solve my problem. This is on page 35.
Let's assume, that your code which reads an image, looks like this (snippet from OpenImageIO 1.7 Programmer Documentation, Chapter 4.1 Image Input Made Simple, page 55):
ImageInput *in = ImageInput::open (filename);
const ImageSpec &spec = in->spec();
int xres = spec.width;
int yres = spec.height;
int channels = spec.nchannels;
std::vector<unsigned char> pixels (xres*yres*channels);
in->read_image (TypeDesc::UINT8, &pixels[0]);
in->close();
ImageInput::destroy (in);
Now all the bytes of the image are contained in std::vector<unsigned char> pixels.
If you want to access the RGB valuse of the pixel at positon x, y, the you can do it like this:
int pixel_addr = (y * yres + x) * channels;
unsigned char red = pixels[pixel_addr];
unsigned char green = pixels[pixel_addr + 1];
unsigned char blue = pixels[pixel_addr + 2];
Since all the pixels are stored in pixels, there is no reason to store them in separate arrays for the 3 color channels.
But if you want to store the red, green and blue values in separated arrays, then you can do it like this:
std::vector<unsigned char> Rarray(x_res*yres);
std::vector<unsigned char> Garray(x_res*yres);
std::vector<unsigned char> Barray(x_res*yres);
for (int i=0; i<x_res*yres; i++)
{
Rarray[i] = pixels[i*channels];
Garray[i] = pixels[i*channels + 1];
Barray[i] = pixels[i*channels + 2];
}
Of course the pixels have to be tightly packed to pixels (line alignment of 1).

Read bmp file header size

I am trying to find file size, file header size width, and height of a bmp file. I have studied the format of bmp file and the arrangement of bytes in file.
When I try this code it shows wrong width and height for different files.
I have tried this for three images so far. This one image results the right measurement.
This one did not:
I don't understand where I went wrong, but the bit depth showed the right value for all three images.
Here is my code:
#include<iostream>
#include<fstream>
#include<math.h>
using namespace std;
int main() {
ifstream inputfile("bmp.bmp",ios::binary);
char c; int imageheader[1024];
double filesize=0; int width=0; int height=0;int bitCount = 0;
for(int i=0; i<1024; i++) {
inputfile.get(c); imageheader[i]=int(c);
}
filesize=filesize+(imageheader[2])*pow(2,0)+(imageheader[3])*pow(2,8)+(imageheader[4])*pow(2,16)+(imageheader[5])*pow(2,24);
cout<<endl<<endl<<"File Size: "<<(filesize/1024)<<" Kilo Bytes"<<endl;
width=width+(imageheader[18])*pow(2,0)+(imageheader[19])*pow(2,8)+(imageheader[20])*pow(2,16)+(imageheader[21])*pow(2,24);
cout<<endl<<"Width: "<<endl<<(width)<<endl;
height=height+(imageheader[22])*pow(2,0)+(imageheader[23])*pow(2,8)+(imageheader[24])*pow(2,16)+(imageheader[25])*pow(2,24);
cout<<endl<<"Height: "<<endl<<(height)<<endl;
bitCount=bitCount+(imageheader[28])*pow(2,0)+(imageheader[29])*pow(2,8);
cout<<endl<<"Bit Depth: "<<endl<<(bitCount)<<endl;
}
Let's start by reading the BMP header in as a series of bytes, not integers. To make this code truly portable, we'll use <stdint> types.
#include <fstream>
#include <stdint.h>
int main()
{
ifstream inputfile("D:/test.bmp", ios::binary);
uint8_t headerbytes[54] = {};
inputfile.read((char*)headerbytes, sizeof(headerbytes));
Now that we've got the header in memory as an array of bytes, we can simply cast the memory address of each header field back into a integer. Referencing the wikipedia page for bmp and the layout diagram.
uint32_t filesize = *(uint32_t*)(headerbytes+2);
uint32_t dibheadersize = *(uint32_t*)(headerbytes + 14);
uint32_t width = *(uint32_t*)(headerbytes + 18);
uint32_t height = *(uint32_t*)(headerbytes + 22);
uint16_t planes = *(uint16_t*)(headerbytes + 26);
uint16_t bitcount = *(uint16_t*)(headerbytes + 28);
Now an astute reader of the code will recognize that the individual fieds of a a BMP headers are stored in little endian format. And that the code above relies on you to have an x86 processor or any other architecture in which the byte layout is Little Endian. On a big endian machine, you'll have to apply a workaround to convert from LE to BE for each of the variables above.
The bug is reading into signed char. This should fix it:
for(int i = 0; i < 1024; i++)
{
//inputfile.get(c); imageheader[i] = int(c);
// This version of get returns int, where -1 means EOF. Should be checking for errors...
imageheader[i] = inputfile.get();
}
Others have commented on improvements to the code so I won't bother.

C++ fast way to save image from array of values

Right now, I am using CImg.
I am unable to use OpenCV due to this issue.
My CImg code looks like this:
cimg_library::CImg<float> img(512,512);
cimg_forXYC(img,x,y,c) { img(x,y,c) = (array[x][y]); } //array contains all float values between 0/1
img.save(save.c_str()); //taking a lot of time
By using clocks I was able to determine that the first step, the for loop takes 0-0.01 seconds. However, the second step, the saving of the image, takes 0.06 seconds, which is way too long due to the amount of images I have.
I am saving as bitmaps.
Is there any faster way to accomplish the same things (creating an image from an array of values and save) in C++?
Here is a small function that will save your image in pgm format, which most things can read and is dead simple. It requires your compiler support C++11, which most do. It's also hard-coded to 512x512 images.
#include <fstream>
#include <string>
#include <cmath>
#include <cstdint>
void save_image(const ::std::string &name, float img_vals[][512])
{
using ::std::string;
using ::std::ios;
using ::std::ofstream;
typedef unsigned char pixval_t;
auto float_to_pixval = [](float img_val) -> pixval_t {
int tmpval = static_cast<int>(::std::floor(256 * img_val));
if (tmpval < 0) {
return 0u;
} else if (tmpval > 255) {
return 255u;
} else {
return tmpval & 0xffu;
}
};
auto as_pgm = [](const string &name) -> string {
if (! ((name.length() >= 4)
&& (name.substr(name.length() - 4, 4) == ".pgm")))
{
return name + ".pgm";
} else {
return name;
}
};
ofstream out(as_pgm(name), ios::binary | ios::out | ios::trunc);
out << "P5\n512 512\n255\n";
for (int x = 0; x < 512; ++x) {
for (int y = 0; y < 512; ++y) {
const pixval_t pixval = float_to_pixval(img_vals[x][y]);
const char outpv = static_cast<const char>(pixval);
out.write(&outpv, 1);
}
}
}
In a similar vein to #Omnifarious's answer, there is an extremely simple format (also based on NetPBM concepts) for float data such as yours. It is called PFM and is documented here.
The benefit is that both CImg and ImageMagick are able to read and write the format without any additional libraries, and without you needing to write any code! An additional benefit is that you retain the full tonal range of your floats, rather than just 256 steps. On the downside, you do need the full 4 bytes per pixel rather than 1 byte.
So, your code would become:
CImg<float> img(512,512);
cimg_forXYC(img,x,y,c) { img(x,y,c) = (array[x][y]); }
img.save_pfm("filename.pfm");
I benchmarked this by creating 10,000 images and saving them to disk with the following code:
#include <iostream>
#include <cstdlib>
#define cimg_display 0 // No need for X11 stuff
#include "CImg.h"
using namespace cimg_library;
using namespace std;
#define W 512
#define H 512
#define N 10000
int main() {
// Create and initialise float image with radial gradient
cimg_library::CImg<float> img(W,H);
cimg_forXY(img,x,y) {img(x,y) = hypot((float)(W/2-x),(float)(H/2-y)); }
char filename[128];
for(int i=0;i<N;i++){
sprintf(filename,"f-%06d.pfm",i);
img.save_pfm(filename);
}
}
It runs in 21.8 seconds, meaning 2.1 ms per image (0.002s).
As I mentioned earlier, ImageMagick is also able to handle PFM format, so you can then use GNU Parallel and ImageMagick mogrify to convert those images to JPEG:
parallel -X mogrify -format jpg -auto-level ::: *pfm
For the original 10,000 images, that takes 22 seconds, or 2.2 ms/image.

Mean shift implementation in C++

Can anyone recommend a lightweight mean shift clustering implementation in C++? I am already using OpenCV, however their mean shift implementation is for tracking, not clustering. I have seen EDISON, however, this is for image segmentation and not clustering.
I could implement it myself, however would rather not invest the time, and not take the risk of bugs.
Thanks
This is old, but I am working with mean shift right now so I thought it best to answer.
I think I understand the distinction you are making here, but when you say you are looking for mode detection this is vague in the technical sense as from the point of view of the algorithm as the algorithm inherently is for searching for "modes", which are the local minima or maxima depending on how you frame the optimization problem (Gradient descent or ascent).
This source, which was found on the EDISON site, claims to be a c++ implementation of the mean shift clustering algorithm, but as discussed above, clustering is the main implementation of the mode seeking behavior that all other uses of mean shift is based on, especially segmentation, so you can certainly use the EDISON source to find a clustering implementation, even if you have to search through it a bit.
I also found this Github project, for what it is worth, but I haven't worked with it before.
LAST NOTE: I also noticed you said "lightweight" implementation. Note that mean shift is not a very efficient algorithm (i think it is something like O(N^3), but I will check that). That said, it can still be efficiently implemented, though how that should be gauged is more ambiguous. Needless to say, Quick Shift, an attempt by UCLA researchers to solve the issues of the more efficient medoid shift, a similar non-parametric mode seeking algorithm, might be more like what you are looking for in a "lightweight" algorithm.
Here is my C++ version of mean shift object tracking method. To run the code successfully, you need to add the tf.h header file to the main code directory.
#include "tf.h" // include the header file
using namespace cv;
using namespace std;
#include <stdio.h>
makerect mkr; // rectangle for encompassing target
// rcs for row coordination of target window center
//ccs for column coordination of target window center
double rcs=0,ccs=0;
// w for width of target window
// l for length of target window
double W=70,L=60;
const int mySizes[3]={16,16,16}; // vector for number of histogram bins
cv::Mat q4hsv = Mat::zeros(3,mySizes,CV_64F); // initializing histogram variable
uchar nbins=16; // var for num of histogram bins
int main(void){
printf("enter 14 or 36: \t"); // enter number of input video name
uint flag; // var for video flag or number
cin>>flag;
Mat ref4frame; // reference frame which is used for initializing mean shift parameters
char filename [50];
sprintf(filename,"im%d.avi",flag);
VideoCapture capture(filename);
if( !capture.isOpened() )
throw "Error when reading steam_avi";
unsigned long int f4counter=0; // frame counter var
histhsv hsv; // instantiating histhsv class
for (f4counter=1;f4counter<=40000000;f4counter++){ // a big number to support many frames
capture >> ref4frame; //reading input image from specified directory
if( !(ref4frame.data )) // checking the read status
{
printf("Cannot load file image %s\n", filename);
break; }
uchar ndiv = uchar(256/nbins); // division value to which intesity values are divided
if (f4counter==1) { // special for 1st frame
char modelname[20];
if(flag==36){
sprintf(modelname,"data%d.png",flag);
}
else if (flag==14){
sprintf(modelname,"data%d.jpg",flag);
}
// imread is defined in tf.h
Mat img = imread(modelname,1);//reads 1st image
if( !(img.data ))//check if file loading is ok
{
printf("Cannot load file image %s\n", modelname);
break; }
hsv.img=img;//assign new image to hsv object (calculates hsv or rgb hist)
hsv.run();//run the histogram calculator
// assign temporary hsv object to reference hist q4hsv object
for (int i=0;i<16;i++){
for(int j=0;j<16;j++){
for(int k=0;k<16;k++){
q4hsv.at<double>(i,j,k)=hsv.q[i][j][k];
}
}
}
}
if(f4counter<5){averageglobalhsv(ref4frame,q4hsv,rcs,ccs);}
averagelocalhsv(ref4frame,q4hsv,rcs,ccs);//normalizing histogram values (0-1)
Point pt1; pt1.x=ccs; pt1.y=rcs;
int thickness=4;//thickness of marker - here is a circle
int lineType=8;
int shift=0;
RNG rng(0xFFFFFFFF);
cv::circle(ref4frame, pt1, 5, randomColor(rng), thickness, lineType,
shift); //marking object center with a circle
myimshow("reference frame",ref4frame);//show current image
waitKey(1);
}
int c=waitKey(0);
//release memory
ref4frame.release();
destroyAllWindows();
return 0;
}
here is the tf.h header file contents:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2\opencv.hpp"
#include "core\core.hpp"
#include <cstdio>
#include <iostream>
#include <fstream>
#include <math.h>
using namespace cv;
using namespace std;
// makerect class: to create the desired size encompassing window
class makerect
{
public:
double rcs,ccs,w,l; // ctl row, ctl column, width, length
uint rmin,rmax,cmin,cmax,height,length;//min max coordination vars
void run(void);
makerect();
};
makerect::makerect(){
rmin=0;rmax=0;cmin=0;cmax=0;rcs=0;ccs=0;w=0;l=0;
}
void makerect::run(){
//not that all points must be either integer or floating point
rmin=uint(rcs-floor(w/2));//min row coordination
rmax=uint(rmin+w);//max row coordination
cmin=uint (ccs-floor(l/2));//min column coordination
cmax=uint(cmin+l);//max column coordination
if(cmax>length){cmax=length;cmin=cmax-l;// checking column to be inside image}
if(rmax>height){rmax=height;rmin=rmax-w;//checking row to be inside image}
}
static Scalar randomColor(RNG& rng)
{
int icolor = (unsigned)rng;
return Scalar(icolor&255, (icolor>>8)&255, (icolor>>16)&255);
}
//myimshow: is a function to to show image
void myimshow(char* name4window,Mat &tmp4image){
namedWindow(name4window,1); imshow(name4window,tmp4image);
}
void averageglobalhsv(Mat ref4frame,Mat &f,double &rcs,double &ccs)
{
Mat img;
cvtColor(ref4frame,img,CV_BGR2HSV);//rgb2hsv conversion
uint n4rowsref=ref4frame.rows;// num of rows
uint n4colsref=ref4frame.cols;// num of cols
double *im4bp = new double [n4rowsref*n4colsref];//1-D dynamic array equal to image pixels
uint nbins=16;// num of histogram bins
uint ndiv=256/nbins; //division value to which intensities are divided
//vars for image moments (zero to second moments)
double m00=0,m01=0,m10=0,m20=0,m02=0,m11=0,w=0;
uint R=0,G=0,B=0; //red bin num, green bin num, blue bin num
for(uint i=0;i<n4rowsref;i++){ //loop through all image rows
for(uint j=0;j<n4colsref;j++){//loop through all image columns
Vec3b inten=img.at<Vec3b>(i,j);//a vector of three element
R=inten.val[2]; G=inten.val[1]; B=inten.val[0];
R/=ndiv; G/=ndiv; B/=ndiv;//calculating the bin to which current pixel intensity belong
im4bp[i*n4colsref+j]=1.3*sqrt(f.at<double>(R,G,B));//calculating spatial weighted kernel histogram formula
}
}
for(uint i=0;i<n4rowsref;i++){//loop through all image rows
for(uint j=0;j<n4colsref;j++){//loop through all image columns
w=im4bp[j+n4colsref*i];// weight for pixel at (i,j)
m01=m01+double(i)*w;//first moment on y/row coordination
m10=m10+double(j)*w;//first moment on x/column coordination
m00=m00+w;//zeroth moment which is sum of all moments
}
}
if(m00>0){
rcs=ceil(m01/m00);//central point for row
ccs=ceil(m10/m00);}//central point for column
delete im4bp;//cleaning memory
}
void averagelocalhsv(Mat ref4frame,Mat &f,double &rcs,double &ccs)
{
Mat img;
cvtColor(ref4frame,img,CV_BGR2HSV);
makerect mkr;
int sz[]={2,2};
uint n4rowsref=ref4frame.rows;
uint n4colsref=ref4frame.cols;
double *im4bp = new double [n4rowsref*n4colsref];
uint nbins=16;
uint ndiv=256/nbins;
double m00=0,m01=0,m10=0,m20=0,m02=0,m11=0,w=0,Dxx,Dyy,Dxy;
uint R=0,G=0,B=0;
for(uint i=0;i<n4rowsref;i++){
for(uint j=0;j<n4colsref;j++){
Vec3b inten=img.at<Vec3b>(i,j);
R=inten.val[2]; G=inten.val[1]; B=inten.val[0];
R/=ndiv; G/=ndiv; B/=ndiv;
im4bp[i*n4colsref+j]=1.3*sqrt(f.at<double>(R,G,B));
}
}
for(int iter=1;iter<5;iter++){
mkr.rcs=rcs;mkr.ccs=ccs;mkr.w=100;mkr.l=100;mkr.height=ref4frame.rows;
mkr.length=ref4frame.cols; mkr.run();
m00=0;m01=0;m10=0;m20=0;m02=0;m11=0;
for(uint i=mkr.rmin;i<mkr.rmax;i=i+1){
for(uint j=mkr.cmin;j<mkr.cmax;j=j+1){
w=im4bp[j+n4colsref*i];
m01=m01+double(i)*w;
m10=m10+double(j)*w;
m00=m00+w;
}
}
}
if(m00>0){
rcs=ceil(m01/m00);
ccs=ceil(m10/m00);
}
delete im4bp;
}
class histhsv{
public:
histhsv();
void run(void);
Mat img;
double q[16][16][16];
};
histhsv::histhsv(){};
void histhsv::run(void){
//Mat hsv4image;
double sum4hist=0;
uchar nbins=16;
uchar ndiv=256/nbins;
double wmax =0;;
double r_center=0;
double c_center =0;
r_center = img.rows/2;
c_center = img.cols/2;
for (int i=0;i<nbins;i++){for(int j=0;j<nbins;j++){for(int k=0;k<nbins;k++){
q[i][j][k]=0; } } };
cvtColor(img,img,CV_BGR2HSV);
int H=0,S=0,V=0;
for(int r=0;r<img.rows;r++){
for(int c=0;c<img.cols;c++){
Vec3b intensity = img.at<Vec3b>(r,c);
H=intensity.val[0]/ndiv;
S=intensity.val[1]/ndiv;
V=intensity.val[2]/ndiv;
q[H][S][V]+=wmax-(pow(r-r_center,2)+pow(c-c_center,2));
sum4hist+=q[H][S][V];
}
}
for (int i=0;i<nbins;i++){
for(int j=0;j<nbins;j++){
for(int k=0;k<nbins;k++){
q[i][j][k]/=sum4hist;
}
}
}
}

C++: .bmp to byte array in a file

Yes i have been through the other questions that are related to this, but i found them not much help. They were some help but i am still a bit confused. So here what what i need to do:
We have a 132x65 screen. I have a 132x65 .bmp. I want to go through the .bmp and separate it into little 1x8 columns to get the binary of that 32-bit column. Then do that 132 times across, and do that 9 times down. Anything that is not white should be counted as a bit. example:
If the top left pixel of the picture is any color that is not white and the 7 pixels below that are white then that would be the first element of the array, the hex of that number, so the array would look like this:
array [] = { 0x01 } and then it would continue to fill through those 132 columns and then do it again for 9 "sections" of rows. And the file result would be ONLY that array in a separate file.
I understand the header format for this, i have read the wiki article on .bmp file formats, my main problem is i don't really know how to interact with the .bmp when i actually want it to go inside and interact with each pixel from the image. I really dont need the whole thing, but maybe just an example of grabbing each pixel from the .bmp and outputting the color of the pixel into a file or something. My c++ is a little rusty (been doing java and javscript lately).
If you want to read a known format BMP and don't care about how it's done (ie, internal-only thing) you can just take the BMP, ignore the header and use it as a pixel array. It is stored line by line starting at the bottom left. There are some detail snags for how it's packed but in my experience if you take a 32bpp image it can be completely ignored.
As a really simple example:
unsigned int *buffer;
void readfile() {
FILE *f = fopen("file.bmp", "rb");
buffer = new unsigned int[132*65];
fseek(f, 54);
fread(buffer, 132*65*4, 1, f);
fclose(f);
}
unsigned int getpixel(int x, int y) {
//assuming your x/y starts from top left, like I usually do
return buffer[(64 - y) * 132 + x];
}
I had the same problem, but by reading BMP file format description I wrote a function that reads a .BMP file and stores it into a array.
Maybe this function can help you:
unsigned int PIC::BinToNum(char *b,int bytes)
{
unsigned int tmpx = 0;
unsigned int pw = 1;
for(int i=0;i<bytes;i++)
{
tmpx += ((unsigned char)b[i]* pw);
pw = pw * 256;
}
return tmpx;
}
int PIC::Open(const char *path)
{
int pad = 0;
unsigned int sof = 0;
unsigned int tx = 0;
char tmp[4] = {0,0,0,0};
fstream file;
file.open(path,ios::in);
if(file.fail())
{
width=height=ColorBits=size=0;
return -1;
}
else
{
file.seekg(0,ios::beg);
file.read(tmp,2);
if(!(tmp[0] == 66 && tmp[1] == 77))
{
width=height=ColorBits=size=0;
return 0;
}
else
{
file.seekg(2,ios::beg); // 0x2 size
file.read(tmp,4);
size = BinToNum(tmp,4);
file.seekg(18,ios::beg); // 0x12 width
file.read(tmp,4);
width = BinToNum(tmp,4);
file.seekg(22,ios::beg); // 0x16 height
file.read(tmp,4);
height = BinToNum(tmp,4);
file.seekg(28,ios::beg); // 0x1C Bits per Pixel
file.read(tmp,2);
ColorBits = BinToNum(tmp,2);
file.seekg(10,ios::beg); // 0x0A start offset
file.read(tmp,4);
sof=BinToNum(tmp,4);
file.seekg(34,ios::beg); // 0x22 Padding
file.read(tmp,4);
pad = BinToNum(tmp,4);
pad = (int)(pad / height); // Compute Spacing in each row
pad = pad - (width*ColorBits/8);
// Initialize Matrix//
matrix = new(unsigned int[height*width]);
for(int h=height-1;h>=0;h--)
{
for(int w=0;w<=width-1;w++)
{
file.seekg(sof,ios::beg);
file.read(tmp,(int)(ColorBits/8));
tx = BinToNum(tmp,(int)(ColorBits/8));
matrix[(h*width)+w] = tx;
sof+=(int)(ColorBits/8);
}
sof +=pad;
}
}
}
file.close();
return 1;
}
Note:This functions is member of a class that i named it "PIC"...