Trial production of bad apple project

Posted by FrOzeN on Mon, 06 Dec 2021 22:39:04 +0100

preface

I've been envious of the big guy's ability to make a project of running bad apple with characters, and I've always wanted to try. Recently, I suddenly thought of it, so I did it myself.
Many of the codes in the project are borrowed from the big guys. I also thank many big guys for their detailed blogs.
It mainly draws lessons from the blogs of the following bosses:

       https://blog.csdn.net/clauyiye/article/details/78995219?spm=1001.2014.3001.5501
        https://www.cnblogs.com/CodeMIRACLE/p/5508236.html

Most of my operations are based on the boss, and some operations have found some faster ways to replace them.
Specific operations are described below:

1. Download Video

The video can be provided by yourself. If you don't know how to download it, you can click it

https://www.bilibili.com/video/BV1xx411c79H?from=search&seid=6687738456694002600&spm_id_from=333.337.0.0

Then add an i after www. to jump to download. It will ask the next downloader. If you feel troublesome, you can get the video in other ways.

2. Screenshot framing

I think some big guys recommend using OpenCV to process videos into frames of pictures. I think it's too troublesome. Installing opencv takes me a lot of time and won't use it yet. Another big man uses kmplayer or potplayer. I have a potplayer on my computer, but I want it updated when I open it. I'm worried that the format of the intercepted frame is wrong. I went to the next format factory and found that the picture can be directly cut into frames.

I immediately imported the video. It is recommended to set the frame interval to 0.1s. If it is too small, there will be a lot of cuts, especially taking up space. Even so, I also cut more than 2000, as if there is 1.2g. Don't be arrogant if there is insufficient space.
Then it is cut and stored in a new project document. It is suggested to build a folder in the project document and name it p (why is this called, because this is referenced in the code. In order for some students to understand the code and want to implement it by themselves, you just need to follow the steps), as shown in the figure

3. Generate documents with code

Code on!!!
The following code, you need to change some places, see the notes for details

#include <cstdio>
 #include <cstring>
 #include <stdint.h>
 #include <windows.h>
 using namespace std;
 int32_t width,height;
 RGBQUAD *pixels;
 bool OpenBitmap(char const *filename)
 {
     FILE *file = fopen(filename, "rb");
     if (file)
     {
         width=0;
         height=0;
         BITMAPFILEHEADER bf;
         BITMAPINFOHEADER bi;
         fread(&bf, sizeof(bf), 1, file);
         fread(&bi, sizeof(bi), 1, file);
         if(bi.biBitCount!=24)
             return false;
         if(bi.biCompression!=BI_RGB)
             return false;
         width=bi.biWidth;
         height=bi.biHeight;
         pixels=new RGBQUAD[width*height];
         uint32_t rowSize = (bi.biBitCount * width + 31) / 32 * 4;
         uint8_t *line = new uint8_t[rowSize];
         for (int y = 0; y < height; y++)
         {
             fread(line, rowSize, 1, file);
             for (int x = 0; x < width; x++)
             {
                 uint8_t *color = line + x * 3;
                 RGBQUAD *pixel = &pixels[(height-y-1) * width+x];
                 pixel->rgbBlue  = color[0];
                 pixel->rgbGreen = color[1];
                 pixel->rgbRed   = color[2];
             }
         }
         delete[] line;
         fclose(file);
         return true;
     }
     return false;
 }
 RGBQUAD GetColor(int x, int y, int w, int h)
 {
     int r = 0, g = 0, b = 0;
     for (int i = 0; i < w; i++)
     {
         if (i + x >= width) continue;
         for (int j = 0; j < h; j++)
         {
             if (j + y >= height) continue;
             RGBQUAD const& color = pixels[(y + j) * width + (x + i)];
             r += color.rgbRed;
             g += color.rgbGreen;
             b += color.rgbBlue;
         }
     }
     return RGBQUAD{r / (w * h), g / (w * h),b / (w * h)};
 }
 char ColorToCharacter(RGBQUAD const& color)
 {
     int brightness = (color.rgbRed + color.rgbGreen + color.rgbBlue) / 3;
     static char const *characters = "Qdogc*;:-. ";
     int len = strlen(characters);
     int span = 0xFF / len;
     int cidx = brightness / span;
     if (cidx == len)
         cidx--;
     return characters[cidx];
 }
 void OutputAscii(const char* filename, int w, int h)
 {
     FILE *file=fopen(filename,"a+");
     int x = width  / w;
     int y = height / h;
     for (int i = 0; i < height; i += y)
     {
         for (int j = 0; j < width; j += x)
         {
             RGBQUAD color = GetColor(j, i, x, y);
             fprintf(file, "%c", ColorToCharacter(color));
            
         }
         fprintf(file, "\n");
   
     }
     delete [] pixels;
     fclose(file);
 }
 int main()
 {
     char filename[1024];
     printf("Conversion in progress.....");
     for(int i=1;i<=2173;i++)//Change the i here to the number of pictures in your p folder
     {
         sprintf(filename,"p/image%d.bmp",i);//Here is to read in the picture. If the name of the picture is not image + number, change it according to the specific name
         if(OpenBitmap(filename));
             OutputAscii("badapple.txt",width/6,height/12);//Output character document
     }
     printf("Conversion complete!");
 }

The program should be stored in the same folder as the p folder.

4. Play

Next, with the txt document, we can play it

#include <cstdio>
#include <windows.h>
struct fps_limit {
 
	int previous_time;
	int tpf_limit;
	int tpf;
	fps_limit(int fps = 60) : previous_time(GetTickCount()), tpf(0) {
		limit_fps(fps);
	}
	void reset() {
		previous_time = GetTickCount(), 
			tpf = 0;
		tpf_limit = 60;
	}
	void limit_fps(int fps) {
		tpf_limit = (int)(1000.0f / (float)fps);
	}
	void delay() {
		tpf = GetTickCount() - previous_time; 
 
		if (tpf < tpf_limit)
			Sleep(tpf_limit - tpf - 1);
 
		previous_time = GetTickCount();
	}
};
int main()
{
	FILE* fp = fopen("badapple.txt", "r");
	char buf[2048];
	fps_limit fps(20);//The picture refresh frame rate is different for different devices. It needs to be tried slowly
	while (!feof(fp))
	{
		HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); 
														
		COORD pos;//Define cursor start point
		pos.X = 0;
		pos.Y = 10;
		SetConsoleCursorPosition(hConsoleOutput, pos);
		for (int i = 0; i<32; i++) //The refresh rate of the whole picture is adjusted here. You need to try it slowly to find out what is the most smooth to play
		{
			fgets(buf, 2048, fp);
			printf("%s", buf);
		}
		fps.delay();
	}
	return 0;
}

The program should also be placed in the same folder as the txt document. If it is not smooth during playback, you need to slowly select the most appropriate fps and refresh rate.

The whole program, if anyone wants, can send a private letter to me and I'll send it to you.

In addition, thank you again for your blog, so that I can realize such an interesting project on my blog.

Topics: OpenCV AI