图像的ASCII码显示v1—ASCII art--just for fun

原创 2012年03月29日 16:47:26

       这两天闲着没事,觉得将图像内容用ASCII码显示出来挺有意思的,就自己尝试着写了写,到网上一搜才知道原来这东西还是一门艺术-ASCII art!!大笑

咱也跟艺术沾边了O(∩_∩)O哈哈哈~

      闲话少说,切入正题,将图像内容用ASCII码显示出来主要就是用不同的字符表示灰度,以此来区分不同的灰度值达到将内容可视化的目的,这个道理很简单,实现起来其实也不难,如果是直接输入到控制台或者txt文件的则比较简单,主要是需要设置一下字体的宽高,最好是正方形的,否则看起来会比较别扭。下面一个是将lena缩放到100*100之后在控制台窗口直接显示的截图,采用的字符是标点,字体设置的宽高相等为8*8:

        但是这种方式无法保存成图像(当然可以截图,不过那多费劲!),所以就研究了一下如何将字符直接写到图像上,这样保存图像就可以了。这时关键的问题就是如何将字符写到图像上,并且尽量让字符的宽高相等,这样看起来才不会觉得图像被挤过了⊙﹏⊙b汗!

        还是用OpenCV来将字符写到图像上,使用putText函数,不过OpenCV中的字体好像不能设置为等宽高,没办法,就取了折中的方法,将用来代替灰度的所有字符的宽度和高度取了个平均作为字符宽高,这样就将原图像中的一个像素替换为这样一个字符,而且还设置了几个选项:可以选择标点,字母或者数字来代替灰度,并且可以选择输出二值,灰度或者彩色ascii图像-----文中只使用了8个灰度级,即将整幅图像量化为了8个灰度级,这样的缺点就是对灰度分布比较集中的图像失真比较大,可以先对图像进行灰度均衡化处理之后再转换,这里没有考虑这些,下面是主要的函数代码。

char ascii_code_symbol[CODE_SIZE-7] = {'#','&','$','*','+',';','.',' ',0};
char ascii_code_letter[CODE_SIZE-7] = {'m','n','e','f','t','l','i',' ',0};
char ascii_code_number[CODE_SIZE-7] = {'8','9','5','3','2','7','1',' ',0};
char *ascii_code_8[3] = { ascii_code_symbol, ascii_code_letter, ascii_code_number};


//check the input image size and return a defined size,
// that's the max one of width and height is not bigger than 100;
cv::Size get_board_size(Mat &image)
{
	if(image.empty())
		return Size(0,0);

	int f = 0;
	float big=(float)image.rows, smal=(float)image.cols;
	if(image.cols>image.rows)
	{
		f = 1;
		big = float(image.cols);
		smal = float(image.rows);
	}
	
	cv::Size board_size;
	if(big <= 100.f)
	{
		board_size = cv::Size(image.cols, image.rows);
	}
	else
	{
		board_size = cv::Size(int(f==1?100:(100*image.cols/big)), int(f==1?(100*image.rows/big):100));
	}
	return board_size;
}

//get the char code step
int get_char_size(const string &asciiStr)
{
	//init font
	int fontFace = FONT_HERSHEY_PLAIN;
	double fontScale = 0.5;
	int thickness = 1;

	//max_size is the max of all the char code width and height,
	//or return the average size of all the char code width and height;
	int max_size = 0;
	int total_size = 0;
	for (size_t i=0; i<asciiStr.size(); ++i)
	{	
		int baseline = 0;
		string str(1, asciiStr[i]);
		cv::Size textsize = getTextSize(str, fontFace, fontScale, thickness, &baseline);
		if(max_size < textsize.height+baseline)
			max_size = textsize.height+baseline;
		if(max_size < textsize.width)
			max_size = textsize.width;
		total_size += (textsize.height+textsize.width+baseline);
	}
	return total_size/(asciiStr.size()*2);
//	return max_size;
}

/*
convert image to ascii image;
code_type: 0-symbol,1-letter,2-number
color_type: 0-binary,1-gray,2-color
*/
Mat image_to_ascii(Mat &image, int code_type, int color_type)
{
	//check input image
	if(image.empty() || code_type<0 || code_type>2 || code_type<0)
		return Mat();

	//if input is a gray image, set color_type to gray;
	if(image.channels()==1&&code_type==2)
		color_type = 1;
	
	//create the output image
	int char_size = get_char_size(ascii_code_8[code_type]);
	cv::Size board_size = get_board_size(image);
	Mat out_image(char_size*board_size.height, char_size*board_size.width, CV_8UC3,Scalar::all(0));
	
	//resize the input image to defined size;
	Mat resized_image;
	resize(image, resized_image, board_size);
	Mat gray_image;
	if(resized_image.channels() == 3)
		cvtColor(resized_image, gray_image, COLOR_BGR2GRAY);
	else
		gray_image = resized_image;

	//font init
	int fontFace = FONT_HERSHEY_PLAIN;
	double fontScale = 0.5;
	int thickness = 1;

	//print char code to the output image
	for (int i=0; i<resized_image.rows; ++i)
	{
		uchar *ptr_bgr = resized_image.ptr<uchar>(i);
		uchar *ptr_gray = gray_image.ptr<uchar>(i);
		for (int j=0; j<resized_image.cols; ++j)
		{
			//get pixel
			uchar pix_gray = ptr_gray[j];
			
			//prepare the char code and coordinate;
			cv::Point textOrg(j*char_size, (i+1)*char_size);
			string text(1, ascii_code_8[code_type][8-(pix_gray>>5)]);
			
			//colored or not
			if (color_type==0) 
			{
				putText(out_image, text, textOrg, fontFace, fontScale, Scalar::all(255));
			}
			else if(color_type==1)
			{
				putText(out_image, text, textOrg, fontFace, fontScale, Scalar::all(pix_gray));
			}
			else
			{
				putText(out_image, text, textOrg, fontFace, fontScale, Scalar(ptr_bgr[3*j],ptr_bgr[3*j+1],ptr_bgr[3*j+2]));
			}
		}
	}

	return out_image;
}


下面是采用数字的ascii字符的彩色和灰度以及二值lena图像,【对lena图像来说数字的看起来比较好,其他两种效果不如数字的】

可以看出效果还是比较好的,O(∩_∩)O,

当然这里只是简单的将像素进行了替换是基于灰度的,更高级的可以有基于结构的,如边缘,生成更加简练的内容表达,以后有时间再研究研究~~

相关文章推荐

ASCII Art—使用纯文本来显示图像:综述

ASCII Art—使用纯文本来显示图像:综述1.什么是ascii art Acii art是一种使用连续排列的ascii字符进行图形设计的技术。它可以显示在任意的文本框中。 ——维基百...

Just For Fun:智力题【1】

小明和小强都是张老师的学生,张老师的生日是M月N日,2人都知道张老师的生日 是下列10组中的一天,张老师把M值告诉了小明,把N值告诉了小强,张老师问他们知道他的生日是那一天吗? 3月4日 3月5日...

第19课时,实践1,编写一个程序,从键盘上输入一个小写字母,显示这个小写字母及它所对应的大写字母以及它们的ASCII码值

/* *Copyright(c) 2015/4/2 CSDN博客 *All rights reserved. *文件名称:main.c *作 者:金叶 *完成日期:2015/4/2 *版本号:V...

ASCII码—百度百科

  • 2011年02月18日 21:49
  • 93KB
  • 下载

java中文乱码解决之道(二)—–字符编码详解:基础知识 + ASCII + GB**

在上篇博文(java中文乱码解决之道(一)—–认识字符集)中,LZ简单介绍了主流的字符编码,对各种编码都是点到为止,以下LZ将详细阐述字符集、字符编码等基础知识和ASCII、GB的详情。 一、基础知...

乐者为王(Just for Fun)

  • 2007年10月25日 15:37
  • 992KB
  • 下载

Just_For_Fun-Linus_Torvalds自传_中文版

  • 2015年03月02日 00:00
  • 1.49MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:图像的ASCII码显示v1—ASCII art--just for fun
举报原因:
原因补充:

(最多只允许输入30个字)