【瞎折腾/opencv】用记事本打开视频(字符代替像素)

说在前面

Theory

  • 原理其实很简单
  1. 捕捉视频一帧,转为灰度图
  2. 降低颜色空间的大小
  3. 对每一个位置的像素用一个字符代替,字符所占的比例逐渐增大(例如 . ; + # @这样,相当于颜色逐渐加深)
  4. 最后,将转化后的由字符形成这一帧保存起来
  • 存在的问题
  1. 用哪些字符替代?

  2. 用哪种方式保存字符帧?

    这两问题我觉得有些联系,我在实验中用的是putText()函数,将字符直接输出到Mat上,然后使用VideoWriter写入到视频文件中,这样便于视频的生成;但是putText这个函数用的时候有些偏差,有些字符所占的宽度不是固定的,会导致最终结果emmm(っ °Д °;)っ
    在这里插入图片描述
    另一种保存方式,直接输出到文本文件中,这样就没有putText的问题,但是如何将其转换成视频?难道一帧一帧的截图 (不嫌麻烦可以一试,代码也有) ?(而且ascii码的话长宽是不等的)emmmm┗|`O′|┛
    在这里插入图片描述

SourceCode

主要是putText函数

void cv::putText 
(
InputOutputArray img, //输入到img上
const String & text, //要显示的字符
Point org, //要显示的位置(像素)
int fontFace, //字体类型
double fontScale, //字体缩放
Scalar color, //字体颜色
int thickness = 1, //字体粗细
int lineType = LINE_8, //线条类型
bool bottomLeftOrigin = false //是否将text的左下角作为起始位置,否的话左上角
)

字体类型(实验中用的是1,也就是FONT_HERSHEY_PLAIN,貌似最小的)

name含义
FONT_HERSHEY_SIMPLEXnormal size sans-serif font
FONT_HERSHEY_PLAINsmall size sans-serif font
FONT_HERSHEY_DUPLEXnormal size sans-serif font (more complex than FONT_HERSHEY_SIMPLEX)
FONT_HERSHEY_COMPLEXnormal size serif font
FONT_HERSHEY_TRIPLEXnormal size serif font (more complex than FONT_HERSHEY_COMPLEX)
FONT_HERSHEY_COMPLEX_SMALLsmaller version of FONT_HERSHEY_COMPLEX
FONT_HERSHEY_SCRIPT_SIMPLEXhand-writing style font
FONT_HERSHEY_SCRIPT_COMPLEXmore complex variant of FONT_HERSHEY_SCRIPT_SIMPLEX
FONT_ITALICflag for italic font

线条类型(用的0,填充)

name含义
FILLED
LINE_44-connected line
LINE_88-connected line
LINE_AAantialiased line

最后一个参数,在确定Point org后,相当于下面哪一个点(左边俩黑色)作为org
在这里插入图片描述

#include <iostream> // for standard I/O
#include <string>   // for strings
#include <opencv2/core.hpp>     // Basic OpenCV structures (cv::Mat)
#include <opencv2/videoio.hpp>  // Video write
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;

int CNT = 0;

void ProcessText(Mat& I)
{
	CV_Assert(I.depth() == CV_8U && I.channels() == 1);

	string txt_name = "test_" + to_string(CNT) + ".txt";
	ofstream out(txt_name);

	for (int i = 15; i < I.rows - 10; ++i)
	{
		char text[240] = { 0 };
		for (int j = 20; j < I.cols - 25; ++j)
		{
			if (I.at<uchar>(i, j) < 25)
				text[j - 20] = '-';
			else if (I.at<uchar>(i, j) < 50)
				text[j - 20] = '-';
			else if (I.at<uchar>(i, j) < 75)
				text[j - 20] = '<';
			else if (I.at<uchar>(i, j) < 100)
				text[j - 20] = '>';
			else if (I.at<uchar>(i, j) < 125)
				text[j - 20] = '+';
			else if (I.at<uchar>(i, j) < 150)
				text[j - 20] = '+';
			else if (I.at<uchar>(i, j) < 175)
				text[j - 20] = '&';
			else if (I.at<uchar>(i, j) < 200)
				text[j - 20] = '&';
			else if (I.at<uchar>(i, j) < 225)
				text[j - 20] = '%';
			else if (I.at<uchar>(i, j) < 250)
				text[j - 20] = '#';
			else
				text[j - 20] = '@';
		}

		out << text << endl;
	}
	CNT++;
	out.close();
}

int ggg = 0;

void Process(Mat& I, Mat& Out)
{
	// accept only char type matrices
	CV_Assert(I.depth() == CV_8U && I.channels() == 1);

	for (int i = 15; i < I.rows - 10; ++i)
	{
		char text[240] = { 0 };
		for (int j = 20; j < I.cols - 25; ++j)
		{
			if (I.at<uchar>(i, j) < 25)
				text[j - 20] = '-';
			else if (I.at<uchar>(i, j) < 50)
				text[j - 20] = '-';
			else if (I.at<uchar>(i, j) < 75)
				text[j - 20] = '<';
			else if (I.at<uchar>(i, j) < 100)
				text[j - 20] = '>';
			else if (I.at<uchar>(i, j) < 125)
				text[j - 20] = '+';
			else if (I.at<uchar>(i, j) < 150)
				text[j - 20] = '+';
			else if (I.at<uchar>(i, j) < 175)
				text[j - 20] = '&';
			else if (I.at<uchar>(i, j) < 200)
				text[j - 20] = '&';
			else if (I.at<uchar>(i, j) < 225)
				text[j - 20] = '%';
			else if (I.at<uchar>(i, j) < 250)
				text[j - 20] = '#';
			else
				text[j - 20] = '@';
		}

		putText(Out, text, Point(0, (i - 14) * 10), 1, 1, Scalar(255), 1, 1);
		if (ggg == 0)
			cout << text << endl;
	}
	ggg = 1;

}


int main()
{
	const string source = "1.mp4";           // the source file name
	const string NAME = "test.avi";   // Form the new name with container

	int divideWith = 25;

	uchar table[256];
	for (int i = 0; i < 256; ++i)
		table[i] = (uchar)(divideWith * (i / divideWith));

	Mat lookUpTable(1, 256, CV_8U);
	uchar* p = lookUpTable.ptr();
	for (int i = 0; i < 256; ++i)
		p[i] = table[i];

	VideoCapture inputVideo(source);              // Open input
	if (!inputVideo.isOpened())
	{
		cout << "Could not open the input video: " << source << endl;
		return -1;
	}

	VideoWriter outputVideo(NAME, VideoWriter::fourcc('M', 'J', 'P', 'G'),
						 inputVideo.get(CAP_PROP_FPS), Size(960*2, 540*2), true);

	if (!outputVideo.isOpened())
	{
		cout << "Could not open the output video for write: " << NAME << endl;
		return -1;
	}
	Mat src;
	while (true)
	{
		inputVideo >> src;              // read
		if (src.empty()) break;         // check if at end

		pyrDown(src, src, Size(src.cols / 2, src.rows / 2));//缩放
		pyrDown(src, src, Size(src.cols / 2, src.rows / 2));//缩放
		pyrDown(src, src, Size(src.cols / 2, src.rows / 2));//缩放
		cvtColor(src, src, COLOR_BGR2GRAY);//转为灰度图
		LUT(src, lookUpTable, src);//降低颜色空间
		
		imshow("src", src);

		Mat res(Size(1920, 1080),CV_8UC1);//用于保存结果
		Process(src, res);//处理
		//pyrDown(res, res, Size(960, 540));//缩放

		cvtColor(res, res, COLOR_GRAY2BGR);//转化成BGR,VideoWriter的问题

		imshow("test", res);
		outputVideo << res;//写入

		//ProcessText(src);
		
		waitKey(15);
	}
	
	return 0;
}

Result

  • 上面原图,下面结果,都是gif

在这里插入图片描述
在这里插入图片描述


END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值