Skip to content

Commit a8381e2

Browse files
committed
Added new dynamic color mode
1 parent 8aaf2ca commit a8381e2

File tree

1 file changed

+158
-7
lines changed

1 file changed

+158
-7
lines changed

main.cpp

Lines changed: 158 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@ const int MODE_MONOCHROME = 1;
1616
const int MODE_256 = 2;
1717
const int MODE_ASCII_ART = 3;
1818
const int MODE_ASCII_FULL = 4;
19-
int COLOR_MODE = 0;
19+
const int MODE_DYNAMIC_RESOLUTION = 4;
20+
int COLOR_MODE = MODE_DYNAMIC_RESOLUTION;
2021

2122
const char ASCII_ART_GRADIENT[] = " .,-=+*/OQ&%@#NM";
2223
const char ASCII_FULL_GRADIENT[] = " `.-'\",:~_;!|^><+r*?=\\L/v()ic7x1z{tJ}lsT[]FnuCYjofy2ae3I5VSkwZ4mXPGhEqpAK6$bd9HODRgMUW%8N0&B#Q@";
2324

25+
const string BLOCK_HEIGHT_GRADIENT[] = {"", "", "", "", "", "", ""};
26+
const string BLOCK_WIDTH_GRADIENT[] = {"", "", "", "", "", "", ""};
27+
2428
sf::Music audioBuffer;
2529

2630
void onExit(int s) {
@@ -54,6 +58,24 @@ inline int similarityBetweenPixels(Vec3b vec1, Vec3b vec2) {
5458
return abs(vec1[0] - vec2[0]) + abs(vec1[1] - vec2[1]) + abs(vec1[2] - vec2[2]);
5559
}
5660

61+
inline float similarityBetweenPixelsf(Vec3b vec1, Vec3b vec2) {
62+
return (float) (abs(vec1[0] - vec2[0]) + abs(vec1[1] - vec2[1]) + abs(vec1[2] - vec2[2]));
63+
}
64+
65+
inline Vec3b averagePixels(Vec3b vec1, Vec3b vec2) {
66+
return Vec3b(vec1[0] + vec2[0], vec1[1] + vec2[1], vec1[2] + vec2[2]) / 2.0;
67+
}
68+
inline Vec3b averagePixels(Vec3b vec1, Vec3b vec2, Vec3b vec3) {
69+
return Vec3b(vec1[0] + vec2[0] + vec3[0], vec1[1] + vec2[1] + vec3[1], vec1[2] + vec2[2] + vec3[2]) / 3.0;
70+
}
71+
72+
inline Vec3b averagePixelsi(Vec3b vec1, Vec3b vec2) {
73+
return Vec3b((int) (vec1[0] + vec2[0]) / 2, (int) (vec1[1] + vec2[1]) / 2, (int) (vec1[2] + vec2[2]) / 2);
74+
}
75+
inline Vec3b averagePixelsi(Vec3b vec1, Vec3b vec2, Vec3b vec3) {
76+
return Vec3b((int) (vec1[0] + vec2[0] + vec3[0]) / 3, (int) (vec1[1] + vec2[1] + vec3[1]) / 3, (int) (vec1[2] + vec2[2] + vec3[2]) / 3);
77+
}
78+
5779
int main(int argc, char *argv[]) {
5880
// Setup the onExit signal to properly close the program
5981
struct sigaction sigIntHandler;
@@ -103,6 +125,7 @@ int main(int argc, char *argv[]) {
103125
cout << " --volume -v [percent] Set the volume in range 0% to 100%" << endl << endl;
104126
cout << "Color Modes: " << endl;
105127
cout << " color c Uses full RGB" << endl;
128+
cout << " dynamic d Uses full color RGB, and tries to increase resolution using unicode characters; lowest compatibility, but nicest visuals" << endl;
106129
cout << " 256-compatability 256 Uses a slightly more compatible 256 color palette, but looks much worse" << endl;
107130
cout << " monochrome m Uses a set of basic, monochrome unicode characters; very compatible" << endl;
108131
cout << " ascii-art a Makes the output look like ascii art; extremely high compatibilty" << endl;
@@ -137,6 +160,8 @@ int main(int argc, char *argv[]) {
137160
COLOR_MODE = MODE_ASCII_ART;
138161
} else if (argv[argIndex + 1][0] == ("f")[0]) {
139162
COLOR_MODE = MODE_ASCII_FULL;
163+
} else if (argv[argIndex + 1][0] == ("d")[0]) {
164+
COLOR_MODE = MODE_DYNAMIC_RESOLUTION;
140165
}
141166

142167
argIndex++; // Make sure to increment one extra to skip the mode
@@ -163,8 +188,7 @@ int main(int argc, char *argv[]) {
163188

164189
string videoPath = argv[1];
165190

166-
if(!capture.open(videoPath))
167-
{
191+
if (!capture.open(videoPath)) {
168192
cout << "Video not found, is unreadable, or in wrong format!"<<endl;
169193
return 1;
170194
}
@@ -319,7 +343,7 @@ int main(int argc, char *argv[]) {
319343
);
320344

321345
int index = coordsToScreenBufferIndex(i, j, terminalSize.ws_row);
322-
if (screenBufferInited) {
346+
if (screenBufferInited && COLOR_MODE != MODE_DYNAMIC_RESOLUTION) {
323347
if (i > 8 && abs(screenBuffer[index + 0] - pixelBottom[0]) + abs(screenBuffer[index + 1] - pixelBottom[1]) + abs(screenBuffer[index + 2] - pixelBottom[2]) < 2) {
324348
continue;
325349
}
@@ -332,7 +356,134 @@ int main(int argc, char *argv[]) {
332356
cout << "\033[" << (j - lastJ) - 1 << "C";
333357
}
334358

335-
if (COLOR_MODE == MODE_COLOR) {
359+
if (COLOR_MODE == MODE_DYNAMIC_RESOLUTION) {
360+
// Obtain a second pixel
361+
Vec3b pixelTop = RGB.at<Vec3b>(
362+
(int) (i * yScale),
363+
(int) (j * xScale)
364+
);
365+
366+
Vec3b pixelTopR = RGB.at<Vec3b>(
367+
(int) (i * yScale),
368+
(int) (j * xScale) + ((int) xScale/2)
369+
);
370+
371+
Vec3b pixelBottomR = RGB.at<Vec3b>(
372+
(int) (i * yScale) + ((int) yScale/2),
373+
(int) (j * xScale) + ((int) xScale/2)
374+
);
375+
376+
// If color reduction is enabled, process that
377+
if (COLOR_REDUCE > 0) {
378+
float dither = (float) ((i + j) % 2) / 2.1;
379+
pixelTop[0] = roundf(pixelTop[0] / COLOR_REDUCE + dither) * COLOR_REDUCE;
380+
pixelTop[1] = roundf(pixelTop[1] / COLOR_REDUCE + dither) * COLOR_REDUCE;
381+
pixelTop[2] = roundf(pixelTop[2] / COLOR_REDUCE + dither) * COLOR_REDUCE;
382+
pixelBottom[0] = roundf(pixelBottom[0] / COLOR_REDUCE - dither) * COLOR_REDUCE;
383+
pixelBottom[1] = roundf(pixelBottom[1] / COLOR_REDUCE - dither) * COLOR_REDUCE;
384+
pixelBottom[2] = roundf(pixelBottom[2] / COLOR_REDUCE - dither) * COLOR_REDUCE;
385+
pixelTopR[0] = roundf(pixelTopR[0] / COLOR_REDUCE + dither) * COLOR_REDUCE;
386+
pixelTopR[1] = roundf(pixelTopR[1] / COLOR_REDUCE + dither) * COLOR_REDUCE;
387+
pixelTopR[2] = roundf(pixelTopR[2] / COLOR_REDUCE + dither) * COLOR_REDUCE;
388+
pixelBottomR[0] = roundf(pixelBottomR[0] / COLOR_REDUCE - dither) * COLOR_REDUCE;
389+
pixelBottomR[1] = roundf(pixelBottomR[1] / COLOR_REDUCE - dither) * COLOR_REDUCE;
390+
pixelBottomR[2] = roundf(pixelBottomR[2] / COLOR_REDUCE - dither) * COLOR_REDUCE;
391+
}
392+
393+
float verticalSplit = similarityBetweenPixelsf(averagePixels(pixelTop, pixelTopR), averagePixels(pixelBottom, pixelBottomR));
394+
float horizontalSplit = similarityBetweenPixelsf(averagePixels(pixelTop, pixelBottom), averagePixels(pixelTopR, pixelBottomR));
395+
float diagonalSplit = similarityBetweenPixelsf(averagePixels(pixelTop, pixelBottomR), averagePixels(pixelTopR, pixelBottom));
396+
float topLeft = similarityBetweenPixelsf(pixelTop, averagePixels(pixelTopR, pixelBottom, pixelBottomR)) * 0.035;
397+
float topRight = similarityBetweenPixelsf(pixelTopR, averagePixels(pixelTop, pixelBottom, pixelBottomR)) * 0.035;
398+
float bottomLeft = similarityBetweenPixelsf(pixelBottom, averagePixels(pixelTopR, pixelTop, pixelBottomR)) * 0.035;
399+
float bottomRight = similarityBetweenPixelsf(pixelBottomR, averagePixels(pixelTop, pixelTopR, pixelBottom)) * 0.035;
400+
401+
if (
402+
verticalSplit > horizontalSplit && verticalSplit > diagonalSplit &&
403+
verticalSplit > topRight && verticalSplit > topLeft &&
404+
verticalSplit > bottomLeft && verticalSplit > bottomRight
405+
) {
406+
float differences[7];
407+
for (int k = 1; k < 8; k++) {
408+
Vec3b pixel = RGB.at<Vec3b>(
409+
(int) (i * yScale) + ((int) (((float) k) * yScale/8)),
410+
(int) (j * xScale)
411+
);
412+
413+
differences[k - 1] = similarityBetweenPixelsf(pixel, pixelTop);
414+
}
415+
416+
int highestIndex;
417+
float highestValue = -1;
418+
for (int k = 1; k < 7; k++) {
419+
float delta = abs(differences[k - 1] - differences[k]);
420+
421+
if (delta > highestValue) {
422+
highestValue = delta;
423+
highestIndex = k;
424+
}
425+
}
426+
427+
cout << "\033[48;2;" << ((int) pixelTop[2]) << ";" << ((int) pixelTop[1]) << ";" << ((int) pixelTop[0]) << "m\033[38;2;" << ((int) pixelBottom[2]) << ";" << ((int) pixelBottom[1]) << ";" << ((int) pixelBottom[0]) << "m" << BLOCK_HEIGHT_GRADIENT[highestIndex];
428+
} else if (
429+
horizontalSplit > diagonalSplit &&
430+
horizontalSplit > topRight && horizontalSplit > topLeft &&
431+
horizontalSplit > bottomLeft && horizontalSplit > bottomRight
432+
) {
433+
Vec3b left = averagePixelsi(pixelTop, pixelBottom);
434+
Vec3b right = averagePixelsi(pixelTopR, pixelBottomR);
435+
//cout << "\033[38;2;" << ((int) left[2]) << ";" << ((int) left[1]) << ";" << ((int) left[0]) << "m\033[48;2;" << ((int) right[2]) << ";" << ((int) right[1]) << ";" << ((int) right[0]) << "m▌";
436+
437+
float differences[7];
438+
for (int k = 1; k < 8; k++) {
439+
Vec3b pixel = RGB.at<Vec3b>(
440+
(int) (i * yScale),
441+
(int) (j * xScale) + ((int) (((float) k) * yScale/16))
442+
);
443+
444+
differences[k - 1] = similarityBetweenPixelsf(pixel, left);
445+
}
446+
447+
int highestIndex;
448+
float highestValue = -1;
449+
for (int k = 1; k < 7; k++) {
450+
float delta = abs(differences[k - 1] - differences[k]);
451+
452+
if (delta > highestValue) {
453+
highestValue = delta;
454+
highestIndex = k;
455+
}
456+
}
457+
458+
cout << "\033[48;2;" << ((int) right[2]) << ";" << ((int) right[1]) << ";" << ((int) right[0]) << "m\033[38;2;" << ((int) left[2]) << ";" << ((int) left[1]) << ";" << ((int) left[0]) << "m" << BLOCK_WIDTH_GRADIENT[highestIndex];
459+
} else if (
460+
diagonalSplit > topRight && diagonalSplit > topLeft &&
461+
diagonalSplit > bottomLeft && diagonalSplit > bottomRight
462+
) {
463+
Vec3b B = averagePixelsi(pixelTop, pixelBottomR);
464+
Vec3b A = averagePixelsi(pixelTopR, pixelBottom);
465+
cout << "\033[38;2;" << ((int) A[2]) << ";" << ((int) A[1]) << ";" << ((int) A[0]) << "m\033[48;2;" << ((int) B[2]) << ";" << ((int) B[1]) << ";" << ((int) B[0]) << "m▞";
466+
} else if (
467+
topRight > topLeft && topRight > bottomLeft && topRight > bottomRight
468+
) {
469+
Vec3b A = averagePixelsi(pixelTop, pixelBottom, pixelBottomR);
470+
cout << "\033[48;2;" << ((int) A[2]) << ";" << ((int) A[1]) << ";" << ((int) A[0]) << "m\033[38;2;" << ((int) pixelTopR[2]) << ";" << ((int) pixelTopR[1]) << ";" << ((int) pixelTopR[0]) << "m▝";
471+
} else if (
472+
topLeft > bottomLeft && topLeft > bottomRight
473+
) {
474+
Vec3b A = averagePixelsi(pixelTopR, pixelBottom, pixelBottomR);
475+
cout << "\033[48;2;" << ((int) A[2]) << ";" << ((int) A[1]) << ";" << ((int) A[0]) << "m\033[38;2;" << ((int) pixelTop[2]) << ";" << ((int) pixelTop[1]) << ";" << ((int) pixelTop[0]) << "m▘";
476+
} else if (
477+
bottomLeft > bottomRight
478+
) {
479+
Vec3b A = averagePixelsi(pixelTopR, pixelTop, pixelBottomR);
480+
cout << "\033[48;2;" << ((int) A[2]) << ";" << ((int) A[1]) << ";" << ((int) A[0]) << "m\033[38;2;" << ((int) pixelBottom[2]) << ";" << ((int) pixelBottom[1]) << ";" << ((int) pixelBottom[0]) << "m▖";
481+
} else {
482+
Vec3b A = averagePixelsi(pixelTopR, pixelTop, pixelBottom);
483+
cout << "\033[48;2;" << ((int) A[2]) << ";" << ((int) A[1]) << ";" << ((int) A[0]) << "m\033[38;2;" << ((int) pixelBottomR[2]) << ";" << ((int) pixelBottomR[1]) << ";" << ((int) pixelBottomR[0]) << "m▗";
484+
}
485+
486+
} else if (COLOR_MODE == MODE_COLOR) {
336487
// Obtain a second pixel
337488
Vec3b pixelTop = RGB.at<Vec3b>(
338489
(int) (i * yScale),
@@ -356,9 +507,9 @@ int main(int argc, char *argv[]) {
356507
cout << "\033[48;2;" << ((int) pixelTop[2]) << ";" << ((int) pixelTop[1]) << ";" << ((int) pixelTop[0]) << "m ";
357508
} else {
358509
if (useUnicode) {
359-
cout << "\033[48;2;" << ((int) pixelTop[2]) << ";" << ((int) pixelTop[1]) << ";" << ((int) pixelTop[0]) << "m" << "\033[38;2;" << ((int) pixelBottom[2]) << ";" << ((int) pixelBottom[1]) << ";" << ((int) pixelBottom[0]) << "m▄";
510+
cout << "\033[48;2;" << ((int) pixelTop[2]) << ";" << ((int) pixelTop[1]) << ";" << ((int) pixelTop[0]) << "m\033[38;2;" << ((int) pixelBottom[2]) << ";" << ((int) pixelBottom[1]) << ";" << ((int) pixelBottom[0]) << "m▄";
360511
} else {
361-
cout << "\033[48;2;" << ((int) pixelTop[2]) << ";" << ((int) pixelTop[1]) << ";" << ((int) pixelTop[0]) << "m" << "\033[38;2;" << ((int) pixelBottom[2]) << ";" << ((int) pixelBottom[1]) << ";" << ((int) pixelBottom[0]) << "m_";
512+
cout << "\033[48;2;" << ((int) pixelTop[2]) << ";" << ((int) pixelTop[1]) << ";" << ((int) pixelTop[0]) << "m\033[38;2;" << ((int) pixelBottom[2]) << ";" << ((int) pixelBottom[1]) << ";" << ((int) pixelBottom[0]) << "m_";
362513
}
363514
}
364515
} else if (COLOR_MODE == MODE_MONOCHROME) {

0 commit comments

Comments
 (0)