Skip to content

Commit a11ab7e

Browse files
committed
First Prototype
0 parents  commit a11ab7e

File tree

3 files changed

+251
-0
lines changed

3 files changed

+251
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/opencv
2+
/opencv_contrib
3+
/.vscode
4+
our boy.png
5+
/build

CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
cmake_minimum_required(VERSION 2.8)
2+
project( ascii_video )
3+
find_package( OpenCV REQUIRED )
4+
find_package(Curses REQUIRED)
5+
6+
include_directories( ${OpenCV_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR} )
7+
add_executable( ascii_video main.cpp )
8+
target_link_libraries( ascii_video ${OpenCV_LIBS} ${CURSES_LIBRARIES} )

main.cpp

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
#include <sys/ioctl.h>
2+
#include <unistd.h>
3+
#include <opencv2/opencv.hpp>
4+
5+
#include <curses.h>
6+
7+
#include <thread>
8+
#include <chrono>
9+
#include <iostream>
10+
#include <string>
11+
12+
void print_image(cv::Mat* image);
13+
void get_pixels(cv::Mat* image, cv::Vec3b* pixels, int width, int height);
14+
char get_char_from_values(cv::Vec3b values);
15+
char get_char_from_area(cv::Vec3b* pixels, int x, int y, int width, int height, int pixelWidth, int pixelHeight );
16+
void getWindowSize(int* width, int* height);
17+
void get_output_size(cv::Mat* target, int* width, int* height);
18+
19+
int imageProgram(int argc, char** argv);
20+
int videoProgram(int argc, char** argv);
21+
int average(int argc, int* args);
22+
int get_grayscale(int r, int g, int b);
23+
24+
int windowWidth = 0;
25+
int windowHeight = 0;
26+
27+
int main(int argc, char** argv)
28+
{
29+
initscr();
30+
return videoProgram(argc, argv);
31+
}
32+
33+
int videoProgram(int argc, char** argv) {
34+
cv::VideoCapture capture("/home/cobyj33/One Piece Dub Episode 1.mp4");
35+
36+
if (!capture.isOpened()) {
37+
std::cout << "Could not open video";
38+
system("pause");
39+
return EXIT_FAILURE;
40+
}
41+
42+
43+
while (true) {
44+
cv::Mat frame;
45+
capture >> frame;
46+
47+
if (frame.empty()) {
48+
break;
49+
}
50+
51+
erase();
52+
print_image(&frame);
53+
refresh();
54+
// clear();
55+
// std::cout << "\\033[%d;%dH00";
56+
// std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 60));
57+
std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 24));
58+
// cv::waitKey(1000 / 24);
59+
}
60+
61+
capture.release();
62+
return EXIT_SUCCESS;
63+
}
64+
65+
int imageProgram(int argc, char** argv) {
66+
// Read the image file
67+
cv::Mat image = cv::imread("face.png");
68+
if (image.empty()) // Check for failure
69+
{
70+
std::cout << "Could not open or find the image" << std::endl;
71+
system("pause"); //wait for any key press
72+
return -1;
73+
}
74+
75+
76+
return 0;
77+
}
78+
79+
80+
void print_image(cv::Mat* target) {
81+
cv::Mat image = *target;
82+
cv::Vec3b pixels[image.rows * image.cols];
83+
move(0, 0);
84+
get_pixels(target, pixels, image.cols, image.rows);
85+
getWindowSize(&windowWidth, &windowHeight);
86+
87+
int outputWidth;
88+
int outputHeight;
89+
get_output_size(target, &outputWidth, &outputHeight);
90+
91+
//image is bigger than output terminal
92+
if (image.cols <= outputWidth && image.rows <= outputHeight) {
93+
94+
for (int row = 0; row < outputHeight; row++) {
95+
char line[outputWidth];
96+
for (int col = 0; col < outputWidth; col++) {
97+
line[col] = get_char_from_values(pixels[row * image.cols + col]);
98+
}
99+
addstr(line);
100+
addch('\n');
101+
// std::cout << "width " << outputWidth << std::endl;
102+
// std::cout << "height " << outputHeight << std::endl;
103+
}
104+
105+
} else {
106+
107+
double scanWidth = image.cols / outputWidth;
108+
double scanHeight = image.rows / outputHeight;
109+
110+
double currentRowPixel = 0;
111+
double currentColPixel = 0;
112+
113+
114+
for (int row = 0; row < outputHeight; row++) {
115+
char line[outputWidth];
116+
currentColPixel = 0;
117+
for (int col = 0; col < outputWidth; col++) {
118+
119+
int checkWidth = currentColPixel != 0 ? (int)(currentColPixel - scanWidth * (col - 1)) : (int)scanWidth;
120+
int checkHeight = currentRowPixel != 0 ? (int)(currentRowPixel - scanHeight * (row - 1)) : (int)scanHeight;
121+
122+
line[col] = get_char_from_area(pixels, (int)currentColPixel, (int)currentRowPixel, checkWidth, checkHeight, image.cols, image.rows);
123+
124+
currentColPixel += scanWidth;
125+
if (currentColPixel + scanWidth > image.cols) {
126+
break;
127+
}
128+
}
129+
addstr(line);
130+
addch('\n');
131+
currentRowPixel += scanHeight;
132+
if (currentRowPixel + scanHeight > image.rows) {
133+
break;
134+
}
135+
}
136+
137+
}
138+
139+
}
140+
141+
void get_pixels(cv::Mat* image, cv::Vec3b* pixels, int width, int height) {
142+
cv::Mat readImage = *image;
143+
144+
for (int row = 0; row < height; row++) {
145+
for (int col = 0; col < width; col++) {
146+
pixels[row * width + col] = readImage.at<cv::Vec3b>(row, col);
147+
}
148+
}
149+
}
150+
151+
int average(int argc, int* argv) {
152+
153+
if (argc <= 0) {
154+
throw std::invalid_argument("ERROR: ATTEMPT TO AVERAGE ARRAY OF 0 INTS");
155+
}
156+
157+
int sum;
158+
for (int i = 0; i < argc; i++) {
159+
sum += argv[i];
160+
}
161+
162+
return sum / argc;
163+
}
164+
165+
// const int value_characters_length = 95;
166+
// const char value_characters[value_characters_length] = "@MBHENR#KWXDFPQASUZbdehx*8Gm&04LOVYkpq5Tagns69owz$CIu23Jcfry\%1v7l+it[]{}?j|()=~!-/<>\"^_';,:`.";
167+
// const int value_characters_length = 8;
168+
// const char value_characters[value_characters_length] = "█▉▊▋▌▍▎▏";
169+
170+
const int value_characters_length = 11;
171+
const char value_characters[value_characters_length] = "@\%#*+=-:. ";
172+
173+
char get_char_from_values(cv::Vec3b values) {
174+
int value = get_grayscale(values[0], values[1], values[2]);
175+
176+
return value_characters[ value * (value_characters_length - 1) / 255 ];
177+
}
178+
179+
char get_char_from_area(cv::Vec3b* pixels, int x, int y, int width, int height, int pixelWidth, int pixelHeight ) {
180+
181+
if (width == 0 && height == 0) {
182+
throw std::invalid_argument("CANNOT GET CHAR FROM AREA WITH NO WIDTH");
183+
} else if (width == 0) {
184+
throw std::invalid_argument("CANNOT GET CHAR FROM AREA WITH NO WIDTH");
185+
} else if (height == 0) {
186+
throw std::invalid_argument("CANNOT GET CHAR FROM AREA WITH NO HEIGHT");
187+
}
188+
189+
int value = 0;
190+
int valueCount = 0;
191+
for (int row = 0; row < width; row++) {
192+
for (int col = 0; col < height; col++) {
193+
int pixelIndex = (row + y) * pixelWidth + (x + col);
194+
if (pixelIndex < pixelWidth * pixelHeight) {
195+
cv::Vec3b currentPixel = pixels[pixelIndex];
196+
value += get_grayscale(currentPixel[0], currentPixel[1], currentPixel[2]);
197+
valueCount++;
198+
}
199+
}
200+
}
201+
202+
// std::cout << "Value: " << value << std::endl;
203+
// std::cout << "Value Count: " << valueCount << std::endl;
204+
205+
if (valueCount > 0) {
206+
return value_characters[ value * (value_characters_length - 1) / (255 * valueCount) ];
207+
} else {
208+
return value_characters[0];
209+
}
210+
211+
}
212+
213+
void getWindowSize(int* width, int* height) {
214+
struct winsize w;
215+
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
216+
*width = w.ws_col;
217+
*height = w.ws_row;
218+
}
219+
220+
int get_grayscale(int r, int g, int b) {
221+
return (int)(0.299 * r + 0.587 * g + 0.114 * b);
222+
}
223+
224+
void get_output_size(cv::Mat* target, int* width, int* height) {
225+
cv::Mat image = *target;
226+
227+
if (image.cols <= windowWidth && image.rows <= windowHeight) {
228+
*width = image.cols;
229+
*height = image.rows;
230+
} else {
231+
232+
double shrinkFactor = std::min((double)windowWidth / image.cols, (double)windowHeight / image.rows);
233+
234+
*width = (int)(image.cols * shrinkFactor);
235+
*height = (int)(image.rows * shrinkFactor);
236+
}
237+
238+
}

0 commit comments

Comments
 (0)