c++ - reading and writing a large bmp file - c++

I have to create a program in c++ (standard libraries only) that detects edges with Sobel operator on a bmp photo and writes the result to the output bmp file (no need to create it, just to write into a previously created file). To do so I have to read an input bmp file and put it into a dynamic 2x2 array. Reading must be done in two different modes (picked up by an user) - first one is to read whole image into a memory in a dynamic array, second one is to read an image piece by piece (pieces with set size). I have no idea how to do a second mode, i guess it has to somehow read an exact number of lines from an input file, use a sobel on them and put them together in an output file, but i have no idea how to implement it. can you tell me how to start it?
this is some code that i've made, it's incomplete since i have to do a second mode but the first one is done (the Sobel operator code was taken from Dwayne Phillips' book about processing images in C, so it's more C-like)
#include <iostream>
#include <fstream>
using namespace std;
typedef unsigned char byte_t; //krotszy zapis
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////// BMP STRUCTS ////////////////////////////////////////////////////////////////////////////
struct BITMAPFILEHEADER {
byte_t bfType[2];
byte_t bfSize[4];
byte_t bfReserved1[2];
byte_t bfReserved2[2];
byte_t bfOffBits[4];
};
struct BITMAPINFOHEADER {
byte_t biSize[4];
byte_t biWidth[4];
byte_t biHeight[4];
byte_t biPlanes[2];
byte_t biBitCount[2];
byte_t biCompression[4];
byte_t biSizeImage[4];
byte_t biXpelsPerMeter[4];
byte_t biYpelsPerMeter[4];
byte_t biCrlUses[4];
byte_t biCrlImportant[4];
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////// SOBEL MASKS ////////////////////////////////////////////////////////////////////////////////////////
short mask_0[3][3] = { //S1
{ 1, 2, 1},
{ 0, 0, 0},
{-1, -2, -1} };
short mask_1[3][3] = { //S2
{ 2, 1, 0},
{ 1, 0, -1},
{ 0, -1, -2} };
short mask_2[3][3] = { //S3
{ 1, 0, -1},
{ 2, 0, -2},
{ 1, 0, -1} };
short mask_3[3][3] = { //S4
{ 0, -1, -2},
{ 1, 0, -1},
{ 2, 1, 0} };
short mask_4[3][3] = { //S5 (-S1)
{-1, -2, -1},
{ 0, 0, 0},
{ 1, 2, 1} };
short mask_5[3][3] = { //S6 (-S2)
{-2, -1, 0},
{-1, 0, 1},
{ 0, 1, 2} };
short mask_6[3][3] = { //S7 (-S3)
{-1, 0, 1},
{-2, 0, 2},
{-1, 0, 1} };
short mask_7[3][3] = { //S8 (-S4)
{ 0, 1, 2},
{-1, 0, 1},
{-2, -1, 0} };
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////// BASIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////////
int wordValue(byte_t* t) //value of 2 byte long variable
{
return t[0] + t[1] * 256;
}
int dwordValue(byte_t* t) //value of 4 byte long variable
{
return t[0] + t[1] * 256 + t[2] * 256 * 256 + t[3] * 256 * 256 * 256;
}
int menudisplay()
{
cout << "<------------------------------------- OPERATOR SOBELA - PROJEKT -------------------------------- >" << endl;
cout << "< Welcome at Sobel! >" << endl;
cout << "< Sobel detects edges in BMP files. >" << endl;
cout << "< It has two modes: >" << endl;
cout << "< 1. Reading whole image into a RAM >" << endl;
cout << "< 2. Reading an image piece by piece (for big files) >" << endl;
cout << "< To pick a mode, just enter 1 or 2. >" << endl;
cout << "< Then enter a name of an input file with .bmp. >" << endl;
cout << "< Later enter a name of an output value with .bmp. >" << endl;
cout << "< Have fun! >" << endl;
cout << "<----------------------- ----------------------->" << endl << endl;
cout << "Your choice: ";
}
void menuservice()
{
menudisplay();
powrot:
int a;
cin >> a;
switch (a)
{
case 1:
save_to_bmp();
break;
case 2:
/*pieces of image*/
break;
default:
cout << "Bad choice! Pick a mode once again: ";
goto powrot;
break;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////// BMP READING //////////////////////////////////////////////////////////////////////////////////
void readBFH(ifstream& ifs, BITMAPFILEHEADER& bfh) //reading bfh
{
ifs.read((char*)&(bfh.bfType), sizeof(bfh.bfType));
ifs.read((char*)&(bfh.bfSize), sizeof(bfh.bfSize));
ifs.read((char*)&(bfh.bfReserved1), sizeof(bfh.bfReserved1));
ifs.read((char*)&(bfh.bfReserved2), sizeof(bfh.bfReserved2));
ifs.read((char*)&(bfh.bfOffBits), sizeof(bfh.bfOffBits));
}
void readBIH(ifstream& ifs, BITMAPINFOHEADER& bih) //reading bih
{
ifs.read((char*)&(bih.biSize), sizeof(bih.biSize));
ifs.read((char*)&(bih.biWidth), sizeof(bih.biWidth));
ifs.read((char*)&(bih.biHeight), sizeof(bih.biHeight));
ifs.read((char*)&(bih.biPlanes), sizeof(bih.biPlanes));
ifs.read((char*)&(bih.biBitCount), sizeof(bih.biBitCount));
ifs.read((char*)&(bih.biCompression), sizeof(bih.biCompression));
ifs.read((char*)&(bih.biSizeImage), sizeof(bih.biSizeImage));
ifs.read((char*)&(bih.biXpelsPerMeter), sizeof(bih.biXpelsPerMeter));
ifs.read((char*)&(bih.biYpelsPerMeter), sizeof(bih.biYpelsPerMeter));
ifs.read((char*)&(bih.biCrlUses), sizeof(bih.biCrlUses));
ifs.read((char*)&(bih.biCrlImportant), sizeof(bih.biCrlImportant));
}
void writeBFH(ofstream& ofs, BITMAPFILEHEADER& bfh) //zapisywanie naglowka pliku
{
ofs.write((char*)&(bfh.bfType), sizeof(bfh.bfType));
ofs.write((char*)&(bfh.bfSize), sizeof(bfh.bfSize));
ofs.write((char*)&(bfh.bfReserved1), sizeof(bfh.bfReserved1));
ofs.write((char*)&(bfh.bfReserved2), sizeof(bfh.bfReserved2));
ofs.write((char*)&(bfh.bfOffBits), sizeof(bfh.bfOffBits));
}
void writeBIH(ofstream& ofs, BITMAPINFOHEADER& bih) //writing bih
{
ofs.write((char*)&(bih.biSize), sizeof(bih.biSize));
ofs.write((char*)&(bih.biWidth), sizeof(bih.biWidth));
ofs.write((char*)&(bih.biHeight), sizeof(bih.biHeight));
ofs.write((char*)&(bih.biPlanes), sizeof(bih.biPlanes));
ofs.write((char*)&(bih.biBitCount), sizeof(bih.biBitCount));
ofs.write((char*)&(bih.biCompression), sizeof(bih.biCompression));
ofs.write((char*)&(bih.biSizeImage), sizeof(bih.biSizeImage));
ofs.write((char*)&(bih.biXpelsPerMeter), sizeof(bih.biXpelsPerMeter));
ofs.write((char*)&(bih.biYpelsPerMeter), sizeof(bih.biYpelsPerMeter));
ofs.write((char*)&(bih.biCrlUses), sizeof(bih.biCrlUses));
ofs.write((char*)&(bih.biCrlImportant), sizeof(bih.biCrlImportant));
}
void displaydata(BITMAPFILEHEADER bfh, BITMAPINFOHEADER bih) //displaying data
{
cout << "Input file data:" << endl;
cout << "<---------------------------------------->";
cout << "File length: " << dwordValue(bfh.bfSize) << endl;
cout << "Header size: " << dwordValue(bih.biSize) << endl;
cout << "Image width: " << dwordValue(bih.biWidth) << endl;
cout << "Image height: " << dwordValue(bih.biHeight) << endl;
cout << "Image size: " << dwordValue(bih.biSizeImage) << endl;
cout << "Real amount of picture's bytes: " << dwordValue(bih.biSizeImage) - dwordValue(bfh.bfOffBits) << endl;
cout << "Zeros per row: " << zerosPerRow(bfh, bih) << endl;
}
int zerosPerRow(BITMAPFILEHEADER bfh, BITMAPINFOHEADER bih)
{
int realsize = dwordValue(bih.biSizeImage) - dwordValue(bfh.bfOffBits);
int height = dwordValue(bih.biHeight);
int width = dwordValue(bih.biWidth);
int zeros = 0;
if (width % 4 != 0)
{
int bytesPerRow = width * 3;
zeros = (bytesPerRow / 4 + 1) * 4 - bytesPerRow;
}
return zeros;
}
void save_to_bmp()
{
char infile[100];
char outfile[100];
cout << "Enter input file: ";
cin >> infile;
cout << "Enter output file: ";
cin >> outfile;
ifstream ifs(infile, ios::binary); //input stream
ofstream ofs(outfile, ios::binary); //output stream
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
if (!ifs.is_open() || !ofs.is_open())
{
cerr << "Opening error!";
save_to_bmp();
}
else {
readBFH(ifs, bfh);
readBIH(ifs, bih);
writeBFH(ofs, bfh);
writeBIH(ofs, bih);
displaydata(bfh, bih);
/*reading values of pixels*/
unsigned char p; //value of a single pixel
short** the_image; //input image array
the_image = new short* [dwordValue(bih.biWidth)];
for (int i = 0; i < dwordValue(bih.biWidth); i++)
{
the_image[i] = new short [dwordValue(bih.biHeight)];
}
short** out_image; //output image array
out_image = new short* [dwordValue(bih.biWidth)];
for (int i = 0; i < dwordValue(bih.biWidth); i++)
{
out_image[i] = new short[dwordValue(bih.biHeight)];
}
for (int i = 0; i < dwordValue(bih.biHeight); i++)
{
for (int j = 0; j < dwordValue(bih.biWidth); j++)
{
for (int n = 0; n < 2; n++)
{
ifs.read((char*)&p, sizeof(char));
ofs.write((char*)&p, sizeof(char));
}
the_image[i][j] = (short)p;
out_image[i][j] = (short)p;
}
}
/*zera*/
for (int i = 0; i < zerosPerRow(bfh, bih); i++)
{
ifs.read((char*)&p, sizeof(char));
ofs.write((char*)&p, sizeof(char));
}
sobel(the_image, out_image, dwordValue(bih.biWidth), dwordValue(bih.biHeight), dwordValue(bih.biBitCount));
for (int i = 0; i < dwordValue(bih.biWidth); i++)
{
delete[] the_image[i];
the_image[i] = NULL;
}
delete[] the_image;
the_image = NULL;
ifs.close();
ofs.close();
char a;
cout << "File has been read. Enter anything to exit program";
cin >> a;
system("cls");
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////// SOBEL CODE //////////////////////////////////////////////////////////////////////////////////////
short** image, ** out_image;
long rows, cols, bits_per_pixel;
int perform_convolution(short** image, short** out_image, long rows, long cols, long bits_per_pixel)
{
char response[80];
int a, b, i, is_present, j, sum;
short max, min, new_hi, new_low;
new_hi = 250;
new_low = 16;
if (bits_per_pixel == 4) {
new_hi = 10;
new_low = 3;
}
min = 0;
max = 255;
if (bits_per_pixel == 4)
max = 16;
/*cleaning an output array*/
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
out_image[i][j] = 0;
printf("\n ");
for (i = 1; i < rows - 1; i++) {
if ((i % 10) == 0) { printf("%4d", i); }
for (j = 1; j < cols - 1; j++) {
/*convolution*/
/*kierunek 0*/
sum = 0;
for (a = -1; a < 2; a++) {
for (b = -1; b < 2; b++) {
sum = sum + image[i + a][j + b] *
mask_0[a + 1][b + 1];
}
}
if (sum > max) sum = max;
if (sum < 0) sum = 0;
if (sum > out_image[i][j])
out_image[i][j] = sum;
/*kierunek 1*/
sum = 0;
for (a = -1; a < 2; a++) {
for (b = -1; b < 2; b++) {
sum = sum + image[i + a][j + b] * mask_1[a + 1][b + 1];
}
}
if (sum > max) sum = max;
if (sum < 0) sum = 0;
if (sum > out_image[i][j])
out_image[i][j] = sum;
/*kierunek 2*/
sum = 0;
for (a = -1; a < 2; a++) {
for (b = -1; b < 2; b++) {
sum = sum + image[i + a][j + b] * mask_2[a + 1][b + 1];
}
}
if (sum > max) sum = max;
if (sum < 0) sum = 0;
if (sum > out_image[i][j])
out_image[i][j] = sum;
/*kierunek 3*/
sum = 0;
for (a = -1; a < 2; a++) {
for (b = -1; b < 2; b++) {
sum = sum + image[i + a][j + b] * mask_3[a + 1][b + 1];
}
}
if (sum > max) sum = max;
if (sum < 0) sum = 0;
if (sum > out_image[i][j])
out_image[i][j] = sum;
/*kierunek 4*/
sum = 0;
for (a = -1; a < 2; a++) {
for (b = -1; b < 2; b++) {
sum = sum + image[i + a][j + b] * mask_4[a + 1][b + 1];
}
}
if (sum > max) sum = max;
if (sum < 0) sum = 0;
if (sum > out_image[i][j])
out_image[i][j] = sum;
/*kierunek 5*/
sum = 0;
for (a = -1; a < 2; a++) {
for (b = -1; b < 2; b++) {
sum = sum + image[i + a][j + b] * mask_5[a + 1][b + 1];
}
}
if (sum > max) sum = max;
if (sum < 0) sum = 0;
if (sum > out_image[i][j])
out_image[i][j] = sum;
/*kierunek 6*/
sum = 0;
for (a = -1; a < 2; a++) {
for (b = -1; b < 2; b++) {
sum = sum + image[i + a][j + b] * mask_6[a + 1][b + 1];
}
}
if (sum > max) sum = max;
if (sum < 0) sum = 0;
if (sum > out_image[i][j])
out_image[i][j] = sum;
/*kierunek 7*/
sum = 0;
for (a = -1; a < 2; a++) {
for (b = -1; b < 2; b++) {
sum = sum + image[i + a][j + b] * mask_7[a + 1][b + 1];
}
}
if (sum > max) sum = max;
if (sum < 0) sum = 0;
if (sum > out_image[i][j])
out_image[i][j] = sum;
}
}
return(1);
}
int fix_edges(short** im, int w, long rows, long cols)
{
int i, j;
for (i = w; i > 0; i--) {
im[i - 1][i - 1] = im[i][i];
im[i - 1][cols - (i - 1)] = im[i][cols - 1 - (i - 1)];
im[rows - (i - 1)][i - 1] = im[rows - 1 - (i - 1)][i];
im[rows - (i - 1)][cols - (i - 1)] = im[rows - 1 - (i - 1)][cols - 1 - (i - 1)];
}
for (i = 0; i < rows; i++) {
for (j = w; j > 0; j--) {
im[i][j - 1] = im[i][j];
im[i][cols - j] = im[i][cols - j - 1];
}
}
for (j = 0; j < cols; j++) {
for (i = w; i > 0; i--) {
im[i - 1][j] = im[i][j];
im[rows - i][j] = im[rows - i - 1][j];
}
}
return(1);
}
int sobel(short** the_image, short** out_image, long rows, long cols, long bits_per_pixel) //wykrywanie krawedzi operatorem sobela
{
perform_convolution(the_image, out_image, rows, cols, bits_per_pixel);
fix_edges(out_image, 1, rows, cols);
return(1);
}
int main()
{
menuservice();
return 0;
}

Related

Find the minimum difference of all possible pairs

Given 3 numeric sorted arrays:
int[] a;
int[] b;
int[] c;
It is necessary to find three numbers whose difference is minimal:
(a_i- b_j)^2 + (b_j - c_k)^2 + (a_i - c_k)^2 -> min
For examle:
int[] a = {7, 10, 12};
int[] b = {3, 4, 6, 9};
int[] c = {1, 2, 5, 8};
Result should be 7 6 8 (or 7 6 5) because (7 - 6)^2 + (6 - 5)^2 + (7 - 5)^2 = 6 = min
What is the best approach to this problem?
I`ve tried to use 3 variables and increment them depending on the minimum term, but unsuccessfully.
Here is my algorithm written in C++:
void printThreeClosest(int[] a, int[] b, int[] c) {
int64_t diff = (a[0] - b[0]) * (a[0] - b[0]) +
(b[0] - c[0]) * (b[0] - c[0]) +
(a[0] - c[0]) * (a[0] - c[0]);
int i_res = 0, j_res = 0, k_res = 0, i = 0, j = 0, k = 0;
while (i < a.size() && j < b.size() && k < c.size()) {
int first_term = (a[i] - b[j]) * (a[i] - b[j]);
int second_term = (b[j] - c[k]) * (b[j] - c[k]);
int third_term = (a[i] - c[k]) * (a[i] - c[k]);
int min_term = std::min(a[i], std::min(b[j], c[k]));
int64_t current_diff = first_term + second_term + third_term;
if (current_diff < diff) {
diff = current_diff;
i_res = i, j_res = j, k_res = k;
}
if (diff == 0) {
break;
}
if (first_term == min_term) {
++k;
} else if (second_term == min_term) {
++i;
} else {
++j;
}
}
std::cout << a[i_res] << " " << b[j_res] << " " << c[k_res] << "\n";
}
IMO, the straight-forward, but O(n^3) solution may be this:
void printThreeClosest(int[] a, int[] b, int[] c) {
int minVal = -1;
int resa, int resb, int resc;
for(int i=0; i<a.length && minVal != 0; i++) {
int x = a[i];
for(int j=0; j<b.length && minVal != 0; j++) {
int y = b[j];
for(int k=0; k<c.length && minVal != 0; k++) {
int z = c[k];
int sumOfSqr = ( ((x-y)*(x-y)) + ((y-z)*(y-z)) + ((z-x)*(z-x)) );
if (minVal < 0) {
minVal = sumOfSqr;
resa=x; resb=y; resc=z;
} else if (sumOfSqr < minVal) {
minVal = sumOfSqr;
resa=x; resb=y; resc=z;
}
}
}
};
std::cout << resa << ' ' << resb << ' ' << resc << std::endl;
}
This solution implemented in Javascript for quick testing is below:
const a = [7, 10, 12];
const b = [3, 4, 6, 9];
const c = [1, 2, 5, 8];
let minVal = -1;
let result = [];
const sumOfSquares = (x, y, z) => ( ((x-y)*(x-y)) + ((y-z)*(y-z)) + ((x-z)*(x-z)) );
for (let i=0; i < a.length && minVal !== 0; i++) {
for (let j=0; j < b.length && minVal !== 0; j++) {
for (let k=0; k < c.length && minVal !== 0; k++) {
const tempSum = sumOfSquares(a[i], b[j], c[k]);
if (minVal < 0) {
minVal = tempSum;
result = [a[i], b[j], c[k]];
} else if (tempSum < minVal) {
minVal = tempSum;
result = [a[i], b[j], c[k]];
}
}
}
}
console.log('result: ', result);

Copy 80 bit hex number from char array to uint16_t vector or array

Say I have a text file containing the 80bit hex number
0xabcdef0123456789abcd
My C++ program reads that using fstream into a char array called buffer.
But then I want to store it in a uint16_t array such that:
uint16_t * key = {0xabcd, 0xef01, 0x2345, 0x6789, 0xabcd}
I have tried several approaches, but I continue to get decimal integers, for instance:
const std::size_t strLength = strlen(buffer);
std::vector<uint16_t> arr16bit((strLength / 2) + 1);
for (std::size_t i = 0; i < strLength; ++i)
{
arr16bit[i / 2] <<= 8;
arr16bit[i / 2] |= buffer[i];
}
Yields:
arr16bit = {24930, 25444, 25958, 12337, 12851}
There must be an easy way to do this that I'm just not seeing.
Here is the full solution I came up with based on the comments:
int hex_char_to_int(char c) {
if (int(c) < 58) //numbers
return c - 48;
else if (int(c) < 91) //capital letters
return c - 65 + 10;
else if (int(c) < 123) //lower case letters
return c - 97 + 10;
}
uint16_t ints_to_int16(int i0, int i1, int i2, int i3) {
return (i3 * 16 * 16 * 16) + (i2 * 16 * 16) + (i1 * 16) + i0;
}
void readKey() {
const int bufferSize = 25;
char buffer[bufferSize] = { NULL };
ifstream* pStream = new ifstream("key.txt");
if (pStream->is_open() == true)
{
pStream->read(buffer, bufferSize);
}
cout << buffer << endl;
const size_t strLength = strlen(buffer);
int* hex_to_int = new int[strLength - 2];
for (int i = 2; i < strLength; i++) {
hex_to_int[i - 2] = hex_char_to_int(buffer[i]);
}
cout << endl;
uint16_t* key16 = new uint16_t[5];
int j = 0;
for (int i = 0; i < 5; i++) {
key16[i] = ints_to_int16(hex_to_int[j++], hex_to_int[j++], hex_to_int[j++], hex_to_int[j++]);
cout << "0x" << hex << key16[i] << " ";
}
cout << endl;
}
This outputs:
0xabcdef0123456789abcd
0xabcd 0xef01 0x2345 0x6789 0xabcd

MPI C++ Runtime Error: signal 11 (Segmentation fault) with multi-dimensional array creation

Making Mandelbrot with MPI
So I've made a Mandelbrot generator and everything worked fine. Now I'm throwing in a speedup from MPI. Process 0 generates a file name mbrot.ppm and adds the appropriate metadata, then divides up the workload into chunks.
Each process receives the chunk's starting and ending positions and gets to work calculating its portion of the Mandelbrot set. To write to the mbrot.ppm file, each process saves its data in an array so it doesn't write to the file before the previous process finishes.
My Problem
Its a runtime error that says:
Primary job terminated normally, but 1 process returned
a non-zero exit code. Per user-direction, the job has been aborted.
--------------------------------------------------------------------------
--------------------------------------------------------------------------
mpirun noticed that process rank 0 with PID 0 on node Lenovo exited on signal 11 (Segmentation fault).
I believe it comes from the line int data[3][xrange][yrange]; (line 120) since the print statement after this line never executes. Would there be an obvious reason I'm missing why this multi-dimensional array is causing me problems?
Full Code
#include <iostream>
#include <mpi.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <fstream>
#define MCW MPI_COMM_WORLD
using namespace std;
struct Complex {
double r;
double i;
};
Complex operator + (Complex s, Complex t) {
Complex v;
v.r = s.r + t.r;
v.i = s.i + t.i;
return v;
};
Complex operator * (Complex s, Complex t) {
Complex v;
v.r = s.r * t.r - s.i * t.i;
v.i = s.r * t.i + s.i * t.r;
return v;
};
int rcolor(int iters) {
if (iters == 255) return 0;
return 32 * (iters % 8);
};
int gcolor(int iters) {
if (iters == 255) return 0;
return 32 * (iters % 8);
};
int bcolor(int iters) {
if (iters == 255) return 0;
return 32 * (iters % 8);
};
int mbrot(Complex c, int maxIters) {
int i = 0;
Complex z;
z = c;
while (i < maxIters && z.r * z.r + z.i * z.i < 4) {
z = z * z + c;
i++;
}
return i;
};
int main(int argc, char * argv[]) {
int rank, size;
MPI_Init( & argc, & argv);
MPI_Comm_rank(MCW, & rank);
MPI_Comm_size(MCW, & size);
if (size < 2) {
printf("Not an MPI process if only 1 process runs.\n");
exit(1);
}
if (size % 2 != 0) {
printf("Please use a even number\n");
exit(1);
}
Complex c1, c2, c;
char path[] = "brot.ppm";
int DIM;
int chunk[4];
c1.r = -1;
c1.i = -1;
c2.r = 1;
c2.i = 1;
if (rank == 0) { //start the file
ofstream fout;
fout.open(path);
DIM = 2000; // pixel dimensions
fout << "P3" << endl; // The file type .ppm
fout << DIM << " " << DIM << endl; // dimensions of the image
fout << "255" << endl; // color depth
fout.close();
// making dimesions marks
for (int i = 0; i < size; i++) {
chunk[0] = 0; // startX
chunk[1] = DIM; // endX
chunk[2] = (DIM / size) * i; // startY
chunk[3] = (DIM / size) * (i + 1); // endY
MPI_Send(chunk, 4, MPI_INT, i, 0, MCW);
};
};
MPI_Recv(chunk, 4, MPI_INT, 0, 0, MCW, MPI_STATUS_IGNORE);
printf("Process %d recieved chunk\n\t StartX: %d, EndX: %d\n\t StartY: %d, EndY: %d\n", rank, chunk[0], chunk[1], chunk[2], chunk[3]);
// do stuff save in array
// data[3 elements][Xs][Ys]
int xrange = chunk[1] - chunk[0];
int yrange = chunk[3] - chunk[2];
printf("Process %d, x: %d, y: %d\n", rank, xrange, yrange);
int data[3][xrange][yrange];
printf("done\n");
// generate data for mandlebrot
for (int j = chunk[2]; j < chunk[3]; ++j) {
for (int i = chunk[0]; i < chunk[1]; ++i) {
// calculate one pixel of the DIM x DIM image
c.r = (i * (c1.r - c2.r) / DIM) + c2.r;
c.i = (j * (c1.i - c2.i) / DIM) + c2.i;
int iters = mbrot(c, 255);
data[0][i][j] = rcolor(iters);
data[1][i][j] = gcolor(iters);
data[2][i][j] = bcolor(iters);
}
}
printf("here2\n");
// taking turns to write their data to file
for (int k = 0; k < size; k++) {
if (rank == k) {
ofstream fout;
fout.open(path, ios::app);
fout << rank << " was here" << endl;
for (int j = chunk[2]; j < chunk[3]; ++j) {
for (int i = chunk[0]; i < chunk[1]; ++i) {
fout << data[0][i][j] << " " << data[1][i][j] << " " << data[2][i][j] << " ";
}
fout << endl;
}
printf("Process %d done and waiting\n", rank);
} else {
MPI_Barrier(MCW);
}
}
MPI_Finalize();
};
How to Run
$ mpic++ -o mbrot.out mbrot.cpp
$ mpirun -np 4 mbrot.out

How to flip this PGM gradient 90 degrees? (stored in vectors)

I have been working on implementing a grayscale gradient with different dithering methods, but the task calls for the gradient to be horizontal starting with black on the left.
In my attempts to rotate the image horizontally I have tried:
std::reverse(result.begin(), result.end())
I have also tried handling the vector like a 2D array:
temp = result[i][j];
result[i][j] = result[i][width - 1 - j];
result[i][width - 1 - j] = temp;
None of these methods have worked so far.
Here's the code I'm working with:
//***headers n stuff***
vector<vector<int>> gradient(int height, int width)
{
assert(height > 0 && width > 0);
int cf = height / 255;
int color = 0;
vector<vector<int>> result(width, vector<int>(height));
for (int i = 0; i < height; i += cf)
{
for (int j = 0; j < cf; j++)
{
fill(result[i + j].begin(), result[i + j].end(), color % 255);
}
color--;
}
stable_sort(result.begin(), result.end());
return result;
}
vector<vector<int>> Ordered(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
vector<vector<int>> temp(height, vector<int>(width));
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int xlocal = i%ditherSize;
int ylocal = j%ditherSize;
int requiredShade = diterLookup[xlocal + ylocal * 3]*255/9;
if (requiredShade >= result[i][j])
{
result[i][j] = 0;
}
else {
result[i][j] = 255;
}
}
}
return temp;
}
vector<vector<int>> Random(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
//vector<vector<int>> result(height, vector<int>(width));
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int requiredShade = rand() % 255;
if (requiredShade >= result[i][j]) {
result[i][j] = 0;
}
else {
result[i][j] = 255;
}
}
}
return result;
}
vector<vector<int>> Floyd_Steinberg(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int oldpixel = result[i][j];
int newpixel;
if (oldpixel<=127) {
newpixel = 0;
}
else {
newpixel = 255;
}
result[i][j] = newpixel;
int quanterror = oldpixel - newpixel;
if (j < width - 1) {
result[i][j+1] += quanterror * 7 / 16;
}
if (i < height - 1) {
if (j > 0){
result[i + 1][j - 1] += quanterror * 3 / 16;
}
result[i+1][j] += quanterror * 5 / 16;
if (j < width - 1) {
result[i + 1][j + 1] += quanterror * 1 / 16;
}
}
}
}
return result;
}
vector<vector<int>> JJN(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int oldpixel = result[i][j];
int newpixel;
if (oldpixel <= 127) {
newpixel = 0;
}
else {
newpixel = 255;
}
result[i][j] = newpixel;
int quanterror = oldpixel - newpixel;
if (j < width - 1) {
result[i][j + 1] += quanterror * 7 / 48;
if(j<width-2)
result[i][j + 2] += quanterror * 5 / 48;
}
if (i < height - 1) {
if (j > 0) {
if (j > 1)
result[i + 1][j - 2] += quanterror * 3 / 48;
result[i + 1][j - 1] += quanterror * 5 / 48;
}
result[i + 1][j] += quanterror * 7 / 48;
if (j < width - 1) {
result[i + 1][j + 1] += quanterror * 5 / 48;
if (j < width - 2)
result[i + 1][j + 2] += quanterror * 3 / 48;
}
}
if (i < height - 2) {
if (j > 0) {
if(j>1)
result[i + 2][j - 2] += quanterror * 1 / 48;
result[i + 2][j - 1] += quanterror * 3 / 48;
}
result[i + 2][j] += quanterror * 5 / 48;
if (j < width - 1) {
result[i + 2][j + 1] += quanterror * 3 / 48;
if (j < width - 2)
result[i + 2][j + 2] += quanterror * 1 / 48;
}
}
}
}
return result;
}
int main(int argc, char *argv[])
{
if (argc < 5) {
cout << "usage:" << endl << "prog.exe <filename> <width> <height> <dithering>"<<endl;
return 0;
}
stringstream w(argv[2]);
stringstream h(argv[3]);
stringstream d(argv[4]);
int numcols, numrows, dithering;
//***handling error cases ***
srand(time(0));
ofstream file;
file.open(argv[1]);
if (!file)
{
cout << "can't open file" << endl;
return 0;
}
file << "P5" << "\n";
file << numrows << " " << numcols << "\n";
file << 255 << "\n";
vector<vector<int>> pixmap{ gradient(numrows, numcols) };
switch (dithering) {
case 1:
pixmap = Ordered(numrows, numcols, pixmap);
break;
case 2:
pixmap = Random(numrows, numcols, pixmap);
break;
case 3:
pixmap = Floyd_Steinberg(numrows, numcols, pixmap);
break;
case 4:
pixmap = JJN(numrows, numcols, pixmap);
break;
default:
break;
}
for_each(pixmap.begin(), pixmap.end(), [&](const auto& v) {
copy(v.begin(), v.end(), ostream_iterator<char>{file, ""});
});
file.close();
}
And here is the result Using Ordered Dither
If your gray scale image is stored as a std::vector<std::vector<int>>, I have made the following code for you.It rotates the image by 90 degrees in the trigonometric direction:
#include <iostream>
#include <vector>
typedef std::vector<std::vector<int>> GrayScaleImage;
// To check is the GrayScaleImage is valid (rectangular and not empty matrix)
bool isValid(const GrayScaleImage & gsi)
{
bool valid(true);
if(!gsi.empty())
{
size_t width(gsi[0].size());
for(unsigned int i = 1; valid && (i < gsi.size()); ++i)
{
if(gsi[i].size() != width)
valid = false;
}
}
else
valid = false;
return valid;
}
// To print the GrayScaleImage in the console (for the test)
void display(const GrayScaleImage & gsi)
{
for(const std::vector<int> & line : gsi)
{
for(size_t i = 0; i < line.size(); ++i)
std::cout << line[i] << ((i < line.size()-1) ? " " : "");
std::cout << '\n';
}
std::cout << std::flush;
}
// To rotate the GrayScaleImage by 90 degrees in the trigonometric direction
bool rotate90(const GrayScaleImage & gsi, GrayScaleImage & result)
{
bool success(false);
if(isValid(gsi))
{
result = GrayScaleImage(gsi[0].size());
for(const std::vector<int> & line : gsi)
{
for(unsigned int i = 0; i < line.size(); ++i)
result[gsi[0].size()-1 - i].push_back(line[i]);
}
success = true;
}
return success;
}
// Test
int main()
{
GrayScaleImage original { {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11} };
GrayScaleImage rotated;
rotate90(original, rotated);
std::cout << "Original:" << std::endl;
display(original);
std::cout << "\nRotated:" << std::endl;
display(rotated);
return 0;
}
The function that will interest you is rotate90().
The output of the test written in the main() function is:
Original:
0 1 2
3 4 5
6 7 8
9 10 11
Rotated:
2 5 8 11
1 4 7 10
0 3 6 9
As you can see, it worked successfully.
I hope it can help.
EDIT:
I tried with a real grayscale image generated and the rotate90() function worked well.Here is the view, before and after rotating the image (2 examples, landscape and portrait):
Example with landscape image
Example with portrait image
So now we know that the function works well.
I see that your result is not as expected (black area added, dimensions mismatching), that kind of behaviour can occur when you make mistakes with the dimensions of the matrixes.
EDIT2:
The invalid output are not due to rotate90() but to the PGM file generation. I think it is because the data are written as binaries but not the header.The following function I have written creates valid PGM files:
typedef std::vector<std::vector<uint8_t>> GrayScaleImage;
bool createPGMImage(const std::string & file_path, const GrayScaleImage & img)
{
bool success(false);
if(isValid(img))
{
std::ofstream out_s(file_path, std::ofstream::binary);
if(out_s)
{
out_s << "P5\n" << img[0].size() << ' ' << img.size() << '\n' << 255 << '\n';
for(const std::vector<uint8_t> & line : img)
{
for(uint8_t p : line)
out_s << p;
out_s << std::flush;
}
success = true;
out_s.close();
}
}
return success;
}
The isValid() function is the same I have given with rotate90().
I also replaced the int values by uint8_t (unsigned char) values to be more consistent as we are writing single bytes values (0-255).

Algorithm ByteRun, decompression gone wrong, .bmp

I have a little problem with algorithm ByteRun(very similar to RLE). Well when i make the decompression smth go wrong and my output isn't the same as input. The orginal cookie is saved in format .bmp (24 pixels). The output should be our format eg. ".xd".
I saw (as far) only 4 options and it depends on how many pixels we have in width.
for 421 we have
for 422 we have
for 423 we have
and for 424 we have
and the original:
Tbh I thought that I consider padding but idk what makes my poor cookie broke. :( Please help me save the cookie. :D
#include <iostream>
#include <stdlib.h>
#include <fstream>
using namespace std;
struct colour // structure of every pixel BGR
{
unsigned char b;
unsigned char g;
unsigned char r;
};
unsigned int reading_and_writing_the_header(FILE *file_in, FILE *file_out, unsigned char header[])
{
unsigned int width = 0;
unsigned int height = 0;
unsigned int bite_for_pixel = 0;
unsigned int amount_of_pixels = 0;
unsigned int padding = 0;
unsigned int row = 0;
fread(header, 1, 54, file_in); // reading the header // 1=sizeof(unsigned int) = sizof(uni8_t)
fwrite(header, 1, 54, file_out); // wrting header
width = *(unsigned int*)&header[18];
height = *(unsigned int*)&header[22];
bite_for_pixel = *(unsigned int*)&header[28];
padding = width % 4; // counting padding
row = width * 3 + padding; // bites in a row
amount_of_pixels = height * row; // amount of bites after header
return amount_of_pixels;
}
void compression_ByteRun(FILE *file_in,FILE *file_out, unsigned int aop)
{
colour *q = new colour[aop];
fread(q, 1, aop, file_in);
int k = 0;
colour x, y;
int counter1 = 0;
int counter2 = 0;
char *the_same_colours = new char[4];
char *diffrent_colours = new char[128 * 3 + 1];
while (k < (aop / 3))
{
x = q[k];
y = q[k + 1];
if (x.r == y.r && x.b == y.b && x.g == y.g) //if the same R and B and G
{
if (counter1 == 126) // not sure about what exactly should be here
{
the_same_colours[0] = (counter1)*(-1);
fwrite(the_same_colours, 1, 4, file_out);
counter1 = 0;
}
if (counter2 != 0)
{
diffrent_colours[0] = counter2 / 3 - 1;
fwrite(diffrent_colours, 1, counter2 + 1, file_out);
counter2 = 0;
}
counter1++;
k++;
continue;
}
else // if we have diffrent colours side by side
{
if (counter1 != 0)
{
the_same_colours[0] = (counter1)*(-1);
the_same_colours[1] = x.b;
the_same_colours[2] = x.g;
the_same_colours[3] = x.r;
fwrite(the_same_colours, 1, 4, file_out);
counter1 = 0;
k++;
}
else
{
diffrent_colours[counter2 + 1] = x.b;
diffrent_colours[counter2 + 2] = x.g;
diffrent_colours[counter2 + 3] = x.r;
counter2 = counter2+ 3;
if (counter2 / 3 == 127) // same here, not sure about what exactly should be here
{
diffrent_colours[0] = counter2 / 3 - 1;
fwrite(diffrent_colours, 1, counter2 + 1, file_out);
counter2 = 0;
}
k++;
}
}
}
}
void decompression_ByteRun(FILE *file_in,FILE *file_out)
{
char x; // variavle where we keep how many colours we need 2 write
char y, z, o; // variables for comparing values
bool game_over; // variable for checking if the file isn't over
game_over = fread(&x, 1, 1, file_in);
while (game_over == true)
{
if (x >= 0) // if we had diffrent colours side by dide
{
for (int i = 1; i <= x * 3 + 3; i++)
{
fread(&y, 1, 1, file_in);
fwrite(&y, 1, 1, file_out);
}
game_over = fread(&x, 1, 1, file_in);
continue;
}
else // if we have the same colours
{
fread(&z, 1, 1, file_in);
fread(&o, 1, 1, file_in);
fread(&y, 1, 1, file_in);
for (int i = 1; i <= (-(x)+1); i++)
{
fwrite(&z, 1, 1, file_out);
fwrite(&o, 1, 1, file_out);
fwrite(&y, 1, 1, file_out);
}
game_over = fread(&x, 1, 1, file_in);
}
}
}
int main()
{
FILE *file_in;
FILE *file_out;
int number = 0;
char* name = new char;
char* name_out = new char;
unsigned char header[54];
unsigned int amount_of_pixels = 0;
cout << "Write input file: " << endl;
cin >> name;
cout << endl;
cout << "Write output file:" << endl;
cin >> name_out;
cout << endl;
cout << "What u wanna do (1- compression or 2- decompression ";
cin >> number;
file_in = fopen(name, "rb");
if (file_in == NULL)
{
cout << "Error we couldn't open that file.\n Contact our IT group 4 more help" << endl;
system("PAUSE");
exit(0);
}
file_out = fopen(name_out, "wb");
if (file_out == NULL)
{
cout << "Error we couldn't open that file.\n Contact our IT group 4 more help" << endl;
system("PAUSE");
exit(0);
}
switch (number)
{
case 1:
cout << "Compression Byterun" << endl;
amount_of_pixels = reading_and_writing_the_header(file_in, file_out, header);
compression_ByteRun(file_in, file_out, amount_of_pixels);
break;
case 2:
cout << "Decompression Byterun" << endl;
amount_of_pixels = reading_and_writing_the_header(file_in, file_out, header);
decompression_ByteRun(file_in, file_out);
break;
}
system("PAUSE");
return 0;
}