用python和opencv画字符画
一、 思路
其实这种字符画如果要求不高,真的挺简单的
1、准备好字符集
2、先将图片变成灰度图
3、将灰度图里面的不同灰度转化为不同字符
4、保存
二、代码
import cv2
import numpy as np
#字符画画笔(像素由大到小)
arr=["W","N","D","t","x","i","+","-","."," "]
#这个是为了求图片刚好能在电脑上显示的最大倍数
def change_rate(h,w):
rate,hh,ww=1,h,w
while hh>680 or ww>1600:
rate-=0.005
hh=rate*h
ww=rate*w
return rate
img =cv2.imread("cv22.jpg")
#获取像素大小并缩小过大的图片
h=np.size(img,0)
w=np.size(img,1)
rate=change_rate(h,w)
imgg=cv2.resize(img,(0,0),fx=rate,fy=rate)
cv2.imshow("img",imgg)
cv2.waitKey(5)
h=np.size(imgg,0)
w=np.size(imgg,1)
#转换为灰度图
gray=cv2.cvtColor(imgg,cv2.COLOR_BGR2GRAY)
#建立画板
res=np.ndarray([h,w])
#建立图画
for i in range(0,h,5):
for j in range(0,w,5):
t=arr[gray[i,j]//26]
cv2.putText(res,t,(j,i),cv2.FONT_HERSHEY_SIMPLEX,0.1,color=(255,255,255))
cv2.imshow("res",res)
cv2.imwrite("D:cv22_2.jpg",res)
cv2.waitKey()
三、注意点
- 有的图片过大,打开时早就占满了整个电脑屏幕,因此要先将图片缩小。
- 为了要让画面整洁,字符集里面最好要有空格字符" "。
- 保存的时候记得,路径里面不能有中文,然后我一开始是只有名称
"tree_1.jpg"
,结果找不到,然后在前面加了详细路径,但因为有中文也不行,最后是把中文删掉后,变成图上这种"D:three_1.jpg"
,就可以了。
四、成果
五、改进
1.改为白底黑字
只需要改两个地方
- 一个是建立白色的画板
#建立画板
res=np.ndarray([h,w])
改为
#建立画板
res = np.ones((h, w, 3), dtype=np.uint8) * 255
- 另一个就是把输出字符改为黑色
cv2.putText(res,t,(j,i),cv2.FONT_HERSHEY_SIMPLEX,0.1,color=(0,0,0))
得到例图如下:
2.彩色字符串
(1).了解putText
cv::putText
的原型:
void cv::putText(
cv::Mat& img, // 待绘制的图像
const string& text, // 待绘制的文字,具体为字符串类型
cv::Point origin, // 文本框的左上角的位置
int fontFace, // 字体 (常见的如 cv::FONT_HERSHEY_PLAIN),
double fontScale, // 尺寸因子,值越大文字越大
cv::Scalar color, // 线条的颜色(RGB)
int thickness = 1, // 线条粗细宽度
int lineType = 8, // 线型(4邻域或8邻域,默认8邻域)
bool bottomLeftOrigin = false // 看图像的坐标原点是否位于左下角,值为true,图像原点位于左下角,值为false,图像原点位于左上角
);
(2). 获取颜色RGB
然后知道我们的目的是为了得到每个像素的字符串对应的颜色
for i in range(0,h,5):
for j in range(0,w,5):
pixel=imgg[i,j]#获取颜色
colors= (int (pixel[0]),int(pixel[1]),int(pixel[2]))
t=arr[gray[i,j]//26]
if gray[i,j]>210:
t=" "
cv2.putText(res,t,(j,i),cv2.FONT_HERSHEY_SIMPLEX,0.1,color=colors)#更改颜色
(3).知识点(原理)
这里的关键点在于pixel=imgg[i,j]
语句获取了图像 imgg
在 (i, j) 坐标位置的像素值。
OpenCV 读取的图像是一个三维的 NumPy 数组,表示图像的像素矩阵。每个像素点都由三个值组成,分别表示蓝色、绿色和红色通道的强度,通常按照 BGR(蓝-绿-红)的顺序排列。
接下来的 colors = (int(pixel[0]), int(pixel[1]), int(pixel[2]))
将这个像素点的 BGR 强度值转化为一个颜色元组。这个颜色元组可以直接用于 cv2.putText 函数,该函数的 color 参数接受一个颜色元组,用于指定字符的颜色。
所以,这段代码的逻辑是:
1.pixel=imgg[i,j]
获取原始图像在 (i, j) 处的像素值。
2.colors = (int(pixel[0]), int(pixel[1]), int(pixel[2]))
将 BGR 强度值转化为颜色元组。
3.cv2.putText(res, t, (j, i), cv2.FONT_HERSHEY_SIMPLEX, 0.1, color=colors)
将字符 t 以指定的颜色绘制到字符图 res 上。
这样,每个字符在字符图上的颜色都由对应位置原始图像的像素值决定。cv2.imread 读取的图像是按照 BGR 通道排列的,所以这里使用 BGR 强度值来构造颜色元组。
(4).完整代码
import cv2
import numpy as np
#字符画画笔(像素由大到小)
arr=["W","N","D","t","x","i","+","-","."," "]
#这个是为了求图片刚好能在电脑上显示的最大倍数
def change_rate(h,w):
rate,hh,ww=1,h,w
while hh>680 or ww>1600:
rate-=0.005
hh=rate*h
ww=rate*w
return rate
img =cv2.imread("work.jpg")
#获取像素大小并缩小过大的图片
h=np.size(img,0)
w=np.size(img,1)
rate=change_rate(h,w)
imgg=cv2.resize(img,(0,0),fx=rate,fy=rate)
cv2.imshow("img",imgg)
cv2.waitKey(5)
h=np.size(imgg,0)
w=np.size(imgg,1)
#转换为灰度图
gray=cv2.cvtColor(imgg,cv2.COLOR_BGR2GRAY)
#建立画板
res = np.ones((h, w, 3), dtype=np.uint8) * 255
#建立图画
for i in range(0,h,5):
for j in range(0,w,5):
pixel=imgg[i,j]#获取颜色
colors= (int (pixel[0]),int(pixel[1]),int(pixel[2]))
t=arr[gray[i,j]//26]
if gray[i,j]>210:
t=" "
cv2.putText(res,t,(j,i),cv2.FONT_HERSHEY_SIMPLEX,0.1,color=colors)#更改颜色
cv2.imshow("res",res)
cv2.imwrite("D:work_2.jpg",res)
cv2.waitKey()
(5).例图