数字图像的加载、显示和输出

图像处理的最基本工作,也是第一步工作:读取、显示和输出图片。

1.图像读取

opencv图像读取的函数是:imread(图像路径,加载模式);输入参数有2个:

  1. “图像路径”是一个字符串;使用绝对路径和相对路径都是可以的,但相对路径必须是程序的工作路径。一般的图像格式都是支持的,如bmp,jpg,png,tiff等。
  2. “读取模式”是一个枚举型的整数,用于指定读取图像的颜色类型。缺省值是1,一般在调用时我们可以不输入这个参数,默认值1表示载入三通道的彩色图像。有如下取值:
    • IMREAD_UNCHANGED:取值:-1。不改变原始图像的读取模式。
    • IMREAD_GRAYSCALE:取值:0。将图像转换成灰度图读取。
    • IMREAD_COLOR:取值:1。为默认缺省值,将图像转换成3通道彩色图像读取。
    • IMREAD_ANYDEPTH:取值:2。读取后是灰度图。这个没搞明白是什么意思。知道的朋友不妨留言指教,不甚感激。
    • IMREAD_ANYCOLOR:取值:4。无损读取原始图像。源图像为彩色图像就读取为3通道彩色图像,源图像为灰度图就读取为灰度图。

为更一步准确掌握这些参数的区别,用3幅图像测试下,这三幅图像分别为:”scooter.png” :带alpha通道的彩色图像; “lenna.bmp”:3通道彩色图像; “moon.bmp”:灰度图像。如下图所示:
这里写图片描述

import cv2

scooter_path = "scooter.png"  # 带alpha通道的彩色图像
lenna_path = "lenna.bmp"  # 3通道彩色图像
moon_path = "moon.bmp"  # 灰度图像

pic = [scooter_path, lenna_path, moon_path]

for p in pic:
    for i in [-1, 0, 1, 2, 4]: # 加载模式的取值
        img = cv2.imread(p, i)
        print(p, i, img.shape)

输出结果:

scooter.png -1 (512, 512, 4)
scooter.png 0 (512, 512)
scooter.png 1 (512, 512, 3)
scooter.png 2 (512, 512)
scooter.png 4 (512, 512, 3)
lenna.bmp -1 (512, 512, 3)
lenna.bmp 0 (512, 512)
lenna.bmp 1 (512, 512, 3)
lenna.bmp 2 (512, 512)
lenna.bmp 4 (512, 512, 3)
moon.bmp -1 (640, 662)
moon.bmp 0 (640, 662)
moon.bmp 1 (640, 662, 3)
moon.bmp 2 (640, 662)
moon.bmp 4 (640, 662)

我们可以从读入图像后的shape中看出一些端倪。

  • 当取值为-1时,即读取模式为IMREAD_UNCHANGED时,源图像是什么样就是什么样。
  • 当取值为0时,即读取模式为IMREAD_GRAYSCALE时,都读取成灰度图像。
  • 当取值为1时,即读取模式为IMREAD_COLOR时,不管源图像是什么,都转换成3通道图像。
  • 当取值为2时,即读取模式为IMREAD_ANYDEPTH时,都读取成了灰度图,没搞明白与上面的IMREAD_GRAYSCALE有什么区别。
  • 当取值为4时,即读取模式为IMREAD_ANYCOLOR时,源图像为彩色图像就读取为3通道彩色图像,源图像为灰度图就读取为灰度图。

一般来说,将图像读取成统一的模式对于后续的处理非常重要,一般都使用3通道的彩色图像进行处理,所以默认值是1,即不管源图像是什么,统一转成3通道的图像。对于灰度图,也是3通道,只不过每个通道的值都相等。

如果需要特殊处理,例如只处理灰度图,或需要alpha通道,那么就可以灵活使用其它的读取模式。

2.图像显示
import cv2
lenna_path = "lenna.bmp"
img = cv2.imread(lenna_path)
cv2.imshow('lenna', img)
cv2.waitKey()

opencv中的图像显示函数是imshow(title,img),title是显示图片的窗口标题,img就是要显示的图像。如果不添最后一句cv2.waitKey(),执行时窗口是一闪而过。waitKey()表示无限等待。中间可以输入数值,如5000,cv2.waitKey(5000),表示5000毫秒即5秒后自动关闭窗口。

lenna_path = "lnnea.bmp"
img = cv2.imread(lenna_path)
cv2.imshow('lenna', img)
cv2.waitKey()

输出:

error: (-215) size.width>0 && size.height>0 in function cv::imshow

从报错信息可以推断,是图像的size有问题,即没有得到图像的size。换句话说就是没有读取到源图像。仔细检查发现是文件名弄错了。

这里需要注意,调用imread(),就算图像的路径是错的,或者没有这张图片, 也不会报错,但得到的是None。接着往下使用imshow()显示的话就会报错。
所以下次看到这个size的报错信息,一定是图片路径或图片名称错了。

opencv对多个图片输出在同一个窗口并没有直接的支持手段,但有时候我们会有这个需求,这时使用matplotlib搭配使用比较合适,这个以后再说。

3.图像输出
lenna_path = "Input\\lenna.bmp"
img = cv2.imread(lenna_path)
cv2.imwrite('Output\\lenna.jpg', img)

opencv中的图像输出函数是imwrite(path, img);path是输出图片的路径和名称,格式转换在这里只需要换个后缀名即可。img就是要保存的图像。

需要注意的是,如果输出时,指定的输出目录不存在,例如不存在Output目录,imwrite()不会报错,但也不会自动创建目录然后输出。这样做的结果是什么也没有发生。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是数字图像中风格迁移的Python代码实现: ```python import tensorflow as tf import numpy as np import PIL.Image import time import functools # 加载图像 def load_img(path_to_img): max_dim = 512 img = tf.io.read_file(path_to_img) img = tf.image.decode_image(img, channels=3) img = tf.image.convert_image_dtype(img, tf.float32) shape = tf.cast(tf.shape(img)[:-1], tf.float32) long_dim = max(shape) scale = max_dim / long_dim new_shape = tf.cast(shape * scale, tf.int32) img = tf.image.resize(img, new_shape) img = img[tf.newaxis, :] return img # 显示图像 def imshow(image, title=None): if len(image.shape) > 3: image = tf.squeeze(image, axis=0) plt.imshow(image) if title: plt.title(title) # 加载模型 def load_model(): vgg = tf.keras.applications.VGG19(include_top=False, weights='imagenet') vgg.trainable = False # 获取每个中间层的输出 content_layers = ['block5_conv2'] style_layers = ['block1_conv1', 'block2_conv1', 'block3_conv1', 'block4_conv1', 'block5_conv1'] num_content_layers = len(content_layers) num_style_layers = len(style_layers) return vgg, style_layers, content_layers # 计算Gram矩阵 def gram_matrix(input_tensor): result = tf.linalg.einsum('bijc,bijd->bcd', input_tensor, input_tensor) input_shape = tf.shape(input_tensor) num_locations = tf.cast(input_shape[1]*input_shape[2], tf.float32) return result/(num_locations) # 提取特征 def get_feature_representations(model, content_path, style_path): content_image = load_img(content_path) style_image = load_img(style_path) # 提取内容图像的特征 content_outputs = model(content_image) content_features = [content_outputs[layer_name] for layer_name in content_layers] # 提取风格图像的特征 style_outputs = model(style_image) style_features = [style_outputs[layer_name] for layer_name in style_layers] # 计算风格图像的Gram矩阵 style_feature_outputs = [gram_matrix(style_feature) for style_feature in style_features] # 将内容图像和风格图像的特征合并 content_dict = {content_name:value for content_name,value in zip(content_layers, content_features)} style_dict = {style_name:value for style_name,value in zip(style_layers, style_feature_outputs)} return {'content':content_dict, 'style':style_dict} # 计算内容损失 def get_content_loss(base_content, target): return tf.reduce_mean(tf.square(base_content - target)) # 计算风格损失 def get_style_loss(base_style, gram_target): height, width, channels = base_style.get_shape().as_list() gram_style = gram_matrix(base_style) return tf.reduce_mean(tf.square(gram_style - gram_target)) # 计算总损失 def compute_loss(model, loss_weights, init_image, gram_style_features, content_features): style_weight, content_weight = loss_weights # 提取初始图像的特征 model_outputs = model(init_image) # 将特征分为内容特征和风格特征 content_output_features = model_outputs[content_layers] style_output_features = model_outputs[style_layers] # 计算内容损失 content_loss = tf.add_n([get_content_loss(content_output_features[name], content_features[name]) for name in content_output_features.keys()]) content_loss *= content_weight / len(content_layers) # 计算风格损失 style_loss = tf.add_n([get_style_loss(style_output_features[name], gram_style_features[name]) for name in style_output_features.keys()]) style_loss *= style_weight / len(style_layers) # 计算总损失 loss = content_loss + style_loss return loss # 计算梯度 def compute_grads(cfg): with tf.GradientTape() as tape: all_loss = compute_loss(**cfg) total_loss = all_loss[0] return tape.gradient(total_loss, cfg['init_image']), all_loss # 进行风格迁移 def run_style_transfer(content_path, style_path, num_iterations=1000, content_weight=1e3, style_weight=1e-2): # 加载模型 model, style_layers, content_layers = load_model() # 提取内容图像和风格图像的特征 feature_representations = get_feature_representations(model, content_path, style_path) content_features = feature_representations['content'] style_features = feature_representations['style'] # 计算风格图像的Gram矩阵 gram_style_features = {name:gram_matrix(style_features[name]) for name in style_features.keys()} # 初始化图像 init_image = load_img(content_path) init_image = tf.Variable(init_image, dtype=tf.float32) # 定义优化器 opt = tf.optimizers.Adam(learning_rate=5, beta_1=0.99, epsilon=1e-1) # 定义损失权重 loss_weights = (style_weight, content_weight) # 进行风格迁移 start_time = time.time() best_loss, best_img = float('inf'), None cfg = { 'model': model, 'loss_weights': loss_weights, 'init_image': init_image, 'gram_style_features': gram_style_features, 'content_features': content_features } # 迭代优化 for i in range(num_iterations): grads, all_loss = compute_grads(cfg) loss, style_score, content_score = all_loss opt.apply_gradients([(grads, init_image)]) clipped = tf.clip_by_value(init_image, clip_value_min=0.0, clip_value_max=1.0) init_image.assign(clipped) if loss < best_loss: best_loss = loss best_img = init_image.numpy() if i % 100 == 0: print("Iteration: {}".format(i)) print("Total loss: {:.4e}, " "style loss: {:.4e}, " "content loss: {:.4e}".format(loss, style_score, content_score)) end_time = time.time() print("Total time: {:.1f}".format(end_time - start_time)) # 显示结果 best_img = tf.squeeze(best_img, axis=0) imshow(best_img, 'Output Image') # 运行风格迁移 content_path = 'content.jpg' style_path = 'style.jpg' run_style_transfer(content_path, style_path, num_iterations=1000, content_weight=1e3, style_weight=1e-2) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值