本文记录了日常中经常用到的一些图像操作,内容有些杂乱,还未好好梳理,所以,先挑自己需要的借鉴。等记录到一定内容,再对本文的结构做一个较大的修改。
目录
一、统计运算时间
1.1、法1:datetime
这是微秒的单词,1秒(s) =1000 毫秒(ms/millisecond) = 1,000,000 微秒(μs/microseconds)
import datetime
starttime = datetime.datetime.now()
endtime = datetime.datetime.now()
elased_time =endtime - starttime
print('***********:', elased_time) # 打印内容:0:00:01.181709
elased_time_m = (endtime - starttime).microseconds
print('***********微秒:', elased_time_m) # 打印内容:181709
elased_time_s = (endtime - starttime).seconds
print('***********秒:', elased_time_s) # 打印内容:1
one_time = elased_time_s + elased_time_m / 1000000
print('**********', one_time) # 打印内容:1.181709
打印结果:
***********微秒: 164341
***********秒: 1
********** 1.164341
可以看出来,他是根据后缀来区分取哪部分的:
- 无后缀,直接输出完成时间
- 后缀microseconds, 输出微秒单位部分时间
- 后缀seconds, 输出秒单位部分时间
注意:完整的时间,是elased_time_s+elased_time_m/1000000
1.2、法2:time
import time
starttime = time.time()
elased_time = time.time() - starttime
print('***********秒:', elased_time)
注意:输出的单位,是秒
二、图像操作
2.1、padding操作、base64encode操作
import base64
image_path = r'1.png'
import base64
from PIL import Image
import io
import numpy as np
import cv2
def padding(arr):
h, w = arr.shape[:2]
p1 = abs(int((h - w) / 2))
p2 = abs(h - w) - p1
if h < w:
arr = np.pad(arr, ((p1, p2), (0, 0), (0, 0)), mode='constant')
if h > w:
arr = np.pad(arr, ((0, 0), (p1, p2), (0, 0)), mode='constant')
return arr
def base64encode_img(image_path):
img = cv2.imread(image_path)
raw_w, raw_h, _ = img.shape
print('0:', raw_h, raw_w)
img = padding(img)
print('1:', img.shape)
img = cv2.resize(img, (512, 512), interpolation=cv2.INTER_CUBIC)
print('2:', img.shape)
src_image = Image.fromarray(img)
output_buffer = io.BytesIO()
src_image.save(output_buffer, format='JPEG')
byte_data = output_buffer.getvalue()
base64_str = base64.b64encode(byte_data).decode('utf-8')
return base64_str
base64_str = base64encode_img(image_path)
print(base64_str)
2.1、文件名包含中文读取
def cv_imread(file_path):
cv_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), 1)
return cv_img
三、各种图像格式之间的转换
3.1、bytes与base64互转
# bytes转base64
image_base4 = base64.b64encode(image_bytes).decode('utf8')
# base64转bytes
image_bytes = base64.b64decode(image_base64)
3.2、bytes与Image对象互转
#将bytes结果转化为Image
bytes_stream = io.BytesIO(result)
roiimg = Image.open(bytes_stream)
# 将Image转为bytes
img = Image.open(img_path, mode='r')
imgByteArr = io.BytesIO()
3.3、bytes与CV2对象互转
# cv2图片对象转为bytes
img = cv2.imread(img_path)
array_bytes = img.tobytes()
# bytes转为cv2图片对象
img_buffer_numpy = np.frombuffer(img_bytes, dtype=np.uint8)
img_numpy = cv2.imdecode(img_buffer_numpy, 1)
3.4、base64与Image对象互转
# Image转base64
img_buffer = io.BytesIO()
image.save(img_buffer, format='JPEG')
byte_data = img_buffer.getvalue()
base64_str = base64.b64encode(byte_data)
# base64转Image
image = base64.b64decode(base64_str)
image = BytesIO(image)
image = Image.open(image)
3.5、base64与cv2对象互转
#cv2转base64
base64_str = cv2.imencode('.jpg',image)[1].tostring()
base64_str = base64.b64encode(base64_str)
#base64转cv2
imgString = base64.b64decode(base64_str)
nparr = np.fromstring(imgString,np.uint8)
image = cv2.imdecode(nparr,cv2.IMREAD_COLOR)
3.6、image与cv2对象互转
# Iamge 转 cv2
img = Image.open("test.jpg")
img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
# cv2 转 Image
img = cv2.imread("test.jpg")
img = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
四、视频文件转单帧图像保存
__author__ = "lingjun"
# E-mail: 1763469890@qq.com
import cv2
vidcap = cv2.VideoCapture('D:\car\car.avi')
success,image = vidcap.read()
count = 0
success = True
while success:
success,image = vidcap.read()
cv2.imwrite("frame%d.jpg" % count, image) # save frame as JPEG file
if cv2.waitKey(10) == 27:
break
count += 1
五、图像显示
5.1、中文字符绘制到图像上
def change_cv2_draw(image,strs,local,colour):
pilimg = Image.fromarray(image)
draw = ImageDraw.Draw(pilimg)
SimHei_ttf = os.path.join(r'pre-trained_PSPNet', 'SimHei.ttf')
font = ImageFont.truetype(SimHei_ttf, 20, encoding="utf-8")
draw.text(local, strs, colour, font=font)
image = np.array(pilimg)
return image
kernel = np.ones((5, 5), np.uint8)
pred_seged = cv2.morphologyEx(img_seged.astype(np.uint8), cv2.MORPH_CLOSE, kernel)
_, img_seged_p = cv2.threshold(pred_seged, 127, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(img_seged_p, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
out_img = img.copy()
if len(contours) > 0:
for contour in contours:
area = cv2.contourArea(contour)
if area > 200:
rect = cv2.minAreaRect(contour)
box = np.int0(cv2.boxPoints(rect))
y1, x1, y2, x2 = np.min(box[:, 1]), np.min(box[:, 0]), np.max(box[:, 1]), np.max(box[:, 0])
cv2.rectangle(out_img, (x1, y1), (x2, y2), (255, 0, 0), 1)
out_img = change_cv2_draw(out_img, '异物', (int(x1), int(y1-25)), (255, 0, 0))
六、图像保存
import cv2
cv2.imwrite()
输入图像范围在0~255之间。
from matplotlib import pyplot as plt
plt.imsave();
输入图像范围在0~1之间。
from skimage import io
io.imsave();
输入图像范围在0~255之间。
之所以会发现他们之间对图像保存的不同,主要是因为在对同一一个array数组进行保存时候发现,保存的结果是不同的。例如:
- 保存的数组范围是0-1,你用cv2.imwrite(),保存的图像几乎都是黑的;
- 但是你用plt.imsave()保存的图像,却是对比度差异很大的黑白二值图像
七、其他操作
7.1、计算两条直线的角度
已知:
- 组成直线l1的点(x1-1, y1-1) (x1-2, y1-2)
- 组成直线l2的点(x2-1, y2-1) (x2-2, y2-2)
- 求l1和l2的角度?
代码实现:
import numpy as np
class Point:
x = 0
y = 0
def __init__(self, x=0, y=0):
self.x = x
self.y = y
class Line:
def __init__(self, p1, p2):
self.p1 = p1
self.p2 = p2
def GetCrossAngle(l1, l2):
arr_0 = np.array([(l1.p2.x - l1.p1.x), (l1.p2.y - l1.p1.y)])
arr_1 = np.array([(l2.p2.x - l2.p1.x), (l2.p2.y - l2.p1.y)])
cos_value = (float(arr_0.dot(arr_1)) / (np.sqrt(arr_0.dot(arr_0)) * np.sqrt(arr_1.dot(arr_1))))
return np.round(np.arccos(cos_value) * (180 / np.pi), 1)
line1 = Line(Point(0, 0), Point(0, 512))
line2 = Line(Point(0, 0), Point(512, 0)) # 基准线 水平线
"""
(0, 0) (512, 0)
---|--------------------------*-> x
| *
| *
| *
| *
| *
| *
| *
| *
| *
| *
| *
*(0, 512) *(512, 512)
↓
y
"""
# 测1
angle = GetCrossAngle(line1, line2) # 计算得到的角度
print('angle:', angle)
output:
angle: 90.0
# 测2
line1 = Line(Point(0, 0), Point(512, 512))
line2 = Line(Point(0, 0), Point(512, 0)) # 基准线 水平线
angle = GetCrossAngle(line1, line2) # 计算得到的角度
print('angle:', angle)
output:
angle: 45.0
7.2、根据偏移角度,进行摆正
代码实现:
import cv2
# 旋转angle角度,缺失背景白色(255, 255, 255)填充
def rotate_bound_bg(image, angle):
"""
:param image: 待旋转图像
:param angle: 角度, 顺时针旋转为+, 逆时针旋转为-
:return:
"""
# grab the dimensions of the image and then determine the center
(h, w) = image.shape[:2]
(cX, cY) = (w // 2, h // 2)
# grab the rotation matrix (applying the negative of the angle to rotate clockwise), then grab the sine and cosine
# (i.e., the rotation components of the matrix)
# -angle位置参数为角度参数负值表示顺时针旋转; 1.0位置参数scale是调整尺寸比例(图像缩放参数),建议0.75
M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# compute the new bounding dimensions of the image
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
# adjust the rotation matrix to take into account translation
M[0, 2] += (nW / 2) - cX
M[1, 2] += (nH / 2) - cY
# perform the actual rotation and return the image
# borderValue 缺失背景填充色彩,可自定义, borderValue 缺省,默认是黑色(0, 0 , 0)
return cv2.warpAffine(image, M, (nW, nH), borderValue=(170, 170, 170))
angle = angle-90
dst = rotate_bound_white_bg(dst, angle)
cv2.imwrite(os.path.join(save_dir, name), dst)
结果展示:
注意:由于我这里是按竖直方向摆正,所以减去了90度,这样恰好可以确定是顺时针,还是逆时针偏转。