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