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);
Related
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;
}
I would like to use this "Levenshtein" function to assess similarities between two strings (to check if user has committed a spelling mistake).
Since I work on null safe mode, it points out an error with the LIST constructor :
List<List<int>> d = List.generate(sa + 1, (int i) => List(sb + 1));
What can I write to replace List(sb+1)); ?
int levenshtein(String a, String b) {
a = a.toUpperCase();
b = b.toUpperCase();
int sa = a.length;
int sb = b.length;
int i, j, cost, min1, min2, min3;
int levenshtein;
// ignore: deprecated_member_use
List<List<int>> d = List.generate(sa + 1, (int i) => List(sb + 1));
if (a.length == 0) {
levenshtein = b.length;
return (levenshtein);
}
if (b.length == 0) {
levenshtein = a.length;
return (levenshtein);
}
for (i = 0; i <= sa; i++) d[i][0] = i;
for (j = 0; j <= sb; j++) d[0][j] = j;
for (i = 1; i <= a.length; i++)
for (j = 1; j <= b.length; j++) {
if (a[i - 1] == b[j - 1])
cost = 0;
else
cost = 1;
min1 = (d[i - 1][j] + 1);
min2 = (d[i][j - 1] + 1);
min3 = (d[i - 1][j - 1] + cost);
d[i][j] = min(min1, min(min2, min3));
}
levenshtein = d[a.length][b.length];
return (levenshtein);
}
You can use List.generate for the inner list as well.
List<List<int>> d = List.generate(sa + 1, (int i) => List.generate(sb + 1, (int j) => 0));
Also, if they're all going to be initialized to 0 you can just do this too:
List<List<int>> d = List.filled(sa + 1, List.filled(sb + 1, 0));
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).
I have to optimitze a code with a triply-recursive function. I know that these kind of functions might be really slow, specially when dealing with large numbers. I have tried to improve the following code by comparing it with an efficient code of Fibonacci, but I'm still stucked.
Could you give me some hints? How can I use a loop instead? Thanks in advance!
int f(int i) {
if (i == 0) return -3;
if (i == 1) return -1;
if (i == 2) return 4;
if (i == 3) return 8;
if (i == 4) return 15;
return f(i-5) + f(i-3) + f(i-1);
}
int main() {
int n;
while (cin >> n) {
for (int i = 0; i < n; ++i) cout << f(i) << " ";
cout << "..." << endl;
}
}
First you might store result in std::vector:
int f(int n) {
std::vector<int> res{-3, -1, 4, 8, 15};
if (n < 5) return res[n];
for (int i = 5; i != n + 1; ++i) {
res.push_back(res[i - 5] + res[i - 3] + res[i - 1]);
}
return res[n];
}
Then to reduce memory foot print, you might use only last values of the array:
int f(int n) {
int res[5] = {-3, -1, 4, 8, 15};
if (n < 5) return res[n];
for (int i = 5; i != n + 1; ++i) {
const int fi = res[0] + res[2] + res[4];
std::copy(res + 1, res + 5, res);
res[4] = fi;
}
return res[4];
}
You might even avoid the copy with circular buffer and use of modulo.
int f(int n) {
int res[5] = {-3, -1, 4, 8, 15};
if (n < 5) return res[n];
for (int i = 5; i != n + 1; ++i) {
const int fi = res[(i - 5) % 5] + res[(i - 3) % 5] + res[(i - 1) % 5];
res[i % 5] = fi;
}
return res[n % 5];
}
You might notice that ((i - 5) % 5) == (i % 5)
and replace the computation by
res[i % 5] += res[(i - 3) % 5] + res[(i - 1) % 5];
The problem is, in a table of (h+1)*(w+1),the first row contains w values: a[1] ... a[w] which fill in the 2rd ... (w+1)th column. The first column contains h values: b[1] ... b[h] which fill in the 2rd ... (h+1)th row. sum(a[i]) is equal to sum(b[i]).
The question is to give one possible solution: result, so that sum(result[i][K]) for a certain K, is equal to a[i] with result[i][K] != result[j][K] (i != j and 0 < i < h+1). And the same rule for rows. PS: All the integers are positive.
For example:
a[] = {10, 3, 3}, b[] = {9, 7}
// 10 3 3
// 9 6 2 1
// 7 4 1 2
result = {6, 2, 1;
4, 1, 2}
It is like Kakuro but not the same. I cannot figure out which algorithm to apply, if anyone knows how to solve it, please give me some help. Thanks a lot.
You can always solve your problem with backtracking. Basic idea here: from top-to-bottom and left-to-right try a valid value in the partially filled table, backtrack when this value doesn't lead to a solution.
Minimal example in C++ with annotated solve:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
class Problem {
public:
template<class AIter, class BIter>
Problem(AIter abegin, AIter aend, BIter bbegin, BIter bend)
: m_width(std::distance(abegin, aend))
, m_height(std::distance(bbegin, bend))
, m_table(new int[(m_width + 1) * (m_height + 1)])
{
std::fill(m_table.get(), m_table.get() + (m_width + 1) * (m_height + 1), 0);
for(size_t i = 0; i < m_width; ++i)
m_table[i + 1] = *abegin++;
for(size_t j = 0; j < m_height; ++j)
m_table[(j + 1) * (m_width + 1)] = *bbegin++;
}
bool Solve() { return solve(0, 0); }
int operator()(size_t i, size_t j) const;
private:
int a(size_t i) const { return m_table[i + 1]; }
int b(size_t j) const { return m_table[(j + 1) * (m_width + 1)]; }
int get(size_t i, size_t j) const { return m_table[(j + 1) * (m_width + 1) + i + 1]; }
void set(size_t i, size_t j, int value) { m_table[(j + 1) * (m_width + 1) + i + 1] = value; }
int colSum(size_t i) const;
int rowSum(size_t j) const;
bool solve(size_t i, size_t j);
size_t m_width, m_height;
std::unique_ptr<int[]> m_table; // (width + 1) x (height + 1)
};
int Problem::colSum(size_t i) const {
int sum = 0;
for(size_t j = 0; j < m_height; ++j)
sum += get(i, j);
return sum;
}
int Problem::rowSum(size_t j) const {
int sum = 0;
for(size_t i = 0; i < m_width; ++i)
sum += get(i, j);
return sum;
}
// solves column-wise using backtracking
bool Problem::solve(size_t i, size_t j) {
size_t width = m_width, height = m_height;
// past last column?
if(i >= width) {
// found solution
return true;
}
// remainder in column and row
int remColSum = a(i) - colSum(i);
int remRowSum = b(j) - rowSum(j);
// early break
if(remColSum <= 0 || remRowSum <= 0)
return false;
// starting at the minimal required value (1 or remColSum if on last row)
int startValue = j + 1 < height ? 1 : remColSum;
// remaining row sum cannot support the starting value
if(remRowSum < startValue)
return false;
// end value minimum remaining sum
int endValue = remColSum < remRowSum ? remColSum : remRowSum;
// on last element must equal starting value
if(i + 1 == width && j + 1 == height && startValue != endValue)
return false;
// column-wise i.e. next cell is (i, j + 1) wrapped
int nextI = i + (j + 1) / height;
int nextJ = (j + 1) % height;
for(int value = startValue; value <= endValue; ++value) {
bool valid = true;
// check row up to i
for(size_t u = 0; u < i && valid; ++u)
valid = (get(u, j) != value);
// check column up to j
for(size_t v = 0; v < j && valid; ++v)
valid = (get(i, v) != value);
if(!valid) {
// value is invalid in partially filled table
continue;
}
// value produces a valid, partially filled table, now try recursing
set(i, j, value);
// upon first solution break
if(solve(nextI, nextJ))
return true;
}
// upon failure backtrack
set(i, j, 0);
return false;
}
int Problem::operator()(size_t i, size_t j) const {
return get(i, j);
}
int main() {
int a[] = { 10, 3, 3 };
int b[] = { 9, 7 };
size_t width = sizeof(a) / sizeof(*a);
size_t height = sizeof(b) / sizeof(*b);
Problem problem(a, a + width, b, b + height);
if(!problem.Solve()) {
std::cout << "No solution" << std::endl;
}
for(size_t j = 0; j < height; ++j) {
if(j == 0) {
std::cout << " ";
for(size_t i = 0; i < width; ++i)
std::cout << " " << a[i];
std::cout << std::endl;
}
std::cout << b[j];
for(size_t i = 0; i < width; ++i) {
int value = problem(i, j);
if(value == 0)
std::cout << " ";
else
std::cout << " " << value;
}
std::cout << std::endl;
}
return 0;
}