Tensorflow在处理数据时,经常加载图像数据,有的时候是直接读取文件,有的则是读取二进制文件,为了更好的理解Tensorflow数据处理模式,先简单讲解显示图片机制,就能更好掌握是否读取正确了。
一、结合opencv读取显示图片
1、变量
使用tf.Variable初始化为tensor,加载到tensorflow对图片进行显示
def showimage_variable_opencv(filename):
image = cv2.imread(filename) # Create a Tensorflow variable
image_tensor = tf.Variable(image, name = 'image') with tf.Session() as sess:
# image_flap = tf.transpose(image_tensor, perm = [1,0,2])
sess.run(tf.global_variables_initializer())
result = sess.run(image_tensor) cv2.imshow('result', result)
cv2.waitKey(0)
2、placeholder
OpenCV读入图片,使用tf.placeholder符号变量加载到tensorflow里,然后tensorflow对图片进行显示
def showimage_placeholder_opencv(filename):
image = cv2.imread(filename) # Create a Tensorflow variable
image_tensor = tf.placeholder('uint8', [None, None, 3]) with tf.Session() as sess:
# image_flap = tf.transpose(image_tensor, perm = [1,0,2])
# sess.run(tf.global_variables_initializer())
result = sess.run(image_tensor, feed_dict = {image_tensor:image}) cv2.imshow('result', result)
cv2.waitKey(0)
上面两个内容非常简单,opencv读取图像数据,成为图像矩阵,然后直接转化成tensorflow的tensor形式,之后通过会话窗口输出图像,进而显示。
参考文献:TensorFlow与OpenCV,读取图片,进行简单操作并显示
二、tensorflow内部读取文件显示
1、tensorflow的gfile
直接使用tensorflow提供的函数image = tf.gfile.FastGFile('PATH')来读取一副图片:
def showimage_gfile(filename):
# 读物文件
image = tf.gfile.FastGFile(filename, 'r').read()
# #图像解码
image_data = tf.image.decode_jpeg(image)
#改变图像数据的类型
image_show = tf.image.convert_image_dtype(image_data, dtype = tf.uint8)
plt.figure(1)
with tf.Session() as sess:
plt.imshow(image_show.eval())
sess.run(image_show)
2.string_input_producer
将图像加载到创建好的队列中使用tf.train.string_input_producer(),然后再加载到变量当中:
def showimage_string_input(filename):
# 函数接受文件列表,如果是文件名需要加[]
file_queue = tf.train.string_input_producer([filename]) # 定义读入器,并读入文件缓存器
image_reader = tf.WholeFileReader()
_, image = image_reader.read(file_queue)
image = tf.image.decode_jpeg(image) with tf.Session() as sess:
# 初始化协同线程
coord = tf.train.Coordinator()
# 启动线程
threads = tf.train.start_queue_runners(sess = sess, coord = coord)
result = sess.run(image)
coord.request_stop()
coord.join(threads)
image_uint8 = tf.image.convert_image_dtype(image, dtype = tf.uint8)
plt.imshow(image_uint8.eval())
cv2.imshow('result', result)
cv2.waitKey(0)
string_input_producer
来生成一个先入先出的队列, 文件阅读器会需要它来读取数据。
string_input_producer
提供的可配置参数来设置文件名乱序和最大的训练迭代数, QueueRunner
会为每次迭代(epoch)将所有的文件名加入文件名队列中, 如果shuffle=True
的话, 会对文件名进行乱序处理。这一过程是比较均匀的,因此它可以产生均衡的文件名队列。
这个QueueRunner
的工作线程是独立于文件阅读器的线程, 因此乱序和将文件名推入到文件名队列这些过程不会阻塞文件阅读器运行。
这个函数在tensorflow应用非常重要,用函数目的是为了将文件列表预先加载文件内出表中,方便文件读取,减少读取数据的时间,具体简介可以参考这篇文章:
文章中对文件保存和读取讲解很清晰,此处重点引用过来
我们用一个具体的例子感受TensorFlow中的数据读取。如图,假设我们在当前文件夹中已经有A.jpg、B.jpg、C.jpg三张图片,我们希望读取这三张图片5个epoch并且把读取的结果重新存到read文件夹中。
# 导入TensorFlow
import TensorFlow as tf # 新建一个Session
with tf.Session() as sess:
# 我们要读三幅图片A.jpg, B.jpg, C.jpg
filename = ['A.jpg', 'B.jpg', 'C.jpg']
# string_input_producer会产生一个文件名队列
filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)
# reader从文件名队列中读数据。对应的方法是reader.read
reader = tf.WholeFileReader()
key, value = reader.read(filename_queue)
# tf.train.string_input_producer定义了一个epoch变量,要对它进行初始化
tf.local_variables_initializer().run()
# 使用start_queue_runners之后,才会开始填充队列
threads = tf.train.start_queue_runners(sess=sess)
i = 0
while True:
i += 1
# 获取图片数据并保存
image_data = sess.run(value)
with open('read/test_%d.jpg' % i, 'wb') as f:
f.write(image_data)
运行代码后,我们得到就可以看到read文件夹中的图片,正好是按顺序的5个epoch:
如果我们设置filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)中的shuffle=True,那么在每个epoch内图像就会被打乱,如图所示:
我们这里只是用三张图片举例,实际应用中一个数据集肯定不止3张图片,不过涉及到的原理都是共通的。
3、slice_input_producer
从众多tensorlist里面,随机选取一个tensor
def saveimages_slice_input(filenames):
labels = [1,2,3]
images_tensor = tf.convert_to_tensor(filenames, dtype=tf.string)
labels_tensor = tf.convert_to_tensor(labels, dtype=tf.uint8) file = tf.train.slice_input_producer([images_tensor, labels_tensor])
image_content = tf.read_file(file[0])
index = file[1]
image_data = tf.image.convert_image_dtype(tf.image.decode_jpeg(image_content), tf.uint8) with tf.Session() as sess:
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess = sess, coord = coord)
sess.run(image_data)
print(sess.run(index))
coord.request_stop()
coord.join(threads)
plt.imshow(image_data.eval())
其实这个是每次只能抽取一个图片,如果需要读取多个图片还是需要构建batch,后面讲对其进行详细的讲解。
其中image_content = tf.read_file(file[0]),必须添加为file[0]才能正确图像数据,进而显示图像。file[1]则是输出数字。