1.cv2.resize(image, (image_size, image_size), 0, 0, cv2.INTER_LINEAR)
参数说明:image表示输入图片,image_size表示变化后的图片大小,0, 0表示dx和dy, cv2.INTER_LINEAR表示插值的方式为线性插值
2.image.get_shape[1:4].num_elements() 获得最后三个维度的大小之和
参数说明:image表示输入的图片
3. saver.save(sess, path, global_step=i) 进行sess的加载
参数说明:sess表示输入,path表示保存路径, global_step表示路径的结尾
4.saver = tf.train.import_meta_graph('./dog-cats-model/dog-cat.ckpt-3700.meta') # 加载训练好的模型的meta值
参数说明:./dog-cats-model/dog-cat.ckpt-3700.meta表示meta 的路径
5.saver.restore(sess, ckpt_path) # 加载训练好的参数模型
参数说明:sess表示执行函数,ckpt_path表示ckpt的路径
6.graph = tf.get_defualt_graph 获得训练好的参数图
7.graph.get_tensor_by_name('x:0') 获得模型的占位参数,以便进行模型的预测
参数说明:’x:0‘ 表示模型在训练过程中,tf.placeholder(name=’x') 输入数据设置的名字
代码中的学习点:1. 使用cv2.resize对图片的维度进行压缩
2.使用np.zeros(num_classes)构造标签,lable[index] = 1 构造标签
3.使用image.get_shape[1:4].num_elements获得最后三个维度的大小
4. saver.save(sess, path, global_step=i) 进行模型参数的存储
5.save.restore(sess, path) 进行模型的加载
猫狗识别的代码:主要分为3个部分,
第一部分:数据的准备
第二部分:构造卷积神经网络,进行模型的训练
第三部分:使用saver.restore加载训练好的参数,进行模型的预测。
第一部分:数据的准备,构建read_train_data函数
第一步:输入的参数是文件的地址,图片的大小(进行图像的矩阵变换),标签,验证集的比例
第二步:对构造一个类dataset, 用于存储训练集和验证集
第三步:对标签进行循环,对输入的文件与标签值进行拼接,获得图片文件的地址,使用glob.glob获得每张图片的地址。
第四步:循环图片地址,读入图片
第一步:使用cv2.imread() 读入图片
第二步: 使用cv2.resize(img, (img_size, img_size), 0, 0, cv2.Inter) 进行图片的维度变换
第三步: 使用.astype('float32') 对图片进行数据类型的转换
第四步: 使用np.multiply(img, 1.0/255.0) 进行图片数值归一化操作, 并将图片加到列表中
第五步:使用np.zeros(num_classes) 构造标签的零矩阵
第六步:使用index = classes.index(filed) 获得标签值对应的索引,label[index] = 1 将索引位置赋值为1
第七步: 将标签加到列表中
第八步:使用os.path.basename(file) 获得图片的名字,添加到列表中,获得标签的名字,添加到列表中
第五步:对图片和标签使用np.array转换为数组类型,并返回图片,标签,名字,类别名
第六步:使用sklearn.utils 中的shuffle,对图片,标签,名字和类别名进行清洗
第七步:使用val_size,验证集的比例对训练集和验证集进行分割
第八步:创建类别DataSet,实例化dataset.train和dataset.val,创建.next_batch函数,
第九步:next_batch函数说明:使用一个变量self._epoch_index 对start和end进行递增循环,如果end > self._num_image, 将start置为0, self._epoch_index置为batch_size。
代码:dataset.py
import numpy as np
import tensorflow as tf
import os
import glob
import cv2
from sklearn.utils import shuffle def load_image(file_path, image_size, classes): num_classes = len(classes)
images = []
labels = []
names = []
cls = []
# 第三步:循环标签,将路径和标签名进行拼接,获得图片文件路径,使用glob.glob获得图片路径
for filed in classes:
index = classes.index(filed)
path = os.path.join(file_path, filed, '*g')
files = glob.glob(path)
# 第四步:循环图片路径,进行图片的读取
for file in files:
# cv2.imread图片的读取
image = cv2.imread(file)
# cv2.resize进行图片维度的重构
image = cv2.resize(image, (image_size, image_size), 0, 0, cv2.INTER_LINEAR)
# .astype进行图片的数据类型的变换
image = image.astype('float32')
# 使用np.multipy进行图片的归一化操作
image = np.multiply(image, 1.0/255.0)
# 将图片添加到列表中
images.append(image)
# 标签零值初始化
label = np.zeros(num_classes)
# 对于类别位置与标签位置对应,即设置为1
label[index] = 1
# 将标签进行添加
labels.append(label)
# 获得图片的名字,使用os.path.basename
name = os.path.basename(file)
# 将名字进行添加
names.append(name)
# 将类别名进行添加
cls.append(filed)
# 第五步: 将图片和标签名都转换为array格式, 并返回图片,标签,名字和类别
images = np.array(images)
labels = np.array(labels) return images, labels, names, cls class DataSet(object): def __init__(self, images, labels, names, cls): self._num_image = images.shape[0]
self._images = images
self._labels = labels
self._names = names
self._cls = cls
self._epoch_index = 0
# 私有属性,返回实际的函数值
@property
def images(self):
return self._images
@property
def labels(self):
return self._labels
@property
def names(self):
return self._names
@property
def cls(self):
return self._cls
@property
def num_image(self):
return self._num_image
# next_batch函数,使用self._epoch_index用来创建初始索引和结束索引,返回batch图像,标签,名字和类别
def next_batch(self, batch_size):
start = self._epoch_index
self._epoch_index += batch_size
if self._epoch_index > self._num_image:
start = 0
self._epoch_index = batch_size
assert batch_size < self._num_image
end = self._epoch_index
return self._images[start:end], self._labels[start:end], self._names[start:end], self._cls[start:end] # 第一步:输入文件名,图片大小,标签,验证集的比例
def read_train_data(file_path, image_size, classes, val_size):
# 第二步:构造类,实例化dataset用于存储训练集和验证集
class DataSets(object):
pass
dataset = DataSets()
# 第三步:载入图片,标签, 名字,类别名
images, labels, names, cls = load_image(file_path, image_size, classes)
# 第六步:对图片,标签,名字和类别名进行清洗
images, labels, names, cls = shuffle(images, labels, names, cls)
# 第七步:使用val_size 对训练集和验证集图片进行分开
val_num = int(images.shape[0] * val_size) val_images = images[0:val_num]
val_labels = labels[0:val_num]
val_names = names[0:val_num]
val_cls = cls[0:val_num] train_images = images[val_num:]
train_labels = labels[val_num:]
train_names = names[val_num:]
train_cls = cls[val_num:]
# 第八步:创建类别DataSet,实例化train和val数据集,并创建next_batch
dataset.train = DataSet(train_images, train_labels, train_names, train_cls)
dataset.val = DataSet(val_images, val_labels, val_names, val_cls) return dataset
第二步:模型的训练
第一步:参数设置,一二三层卷积的大小和个数,以及全连接层的隐藏层的个数
第二步:使用tf.placeholder设置初始的输入参数x和y_pred,并命名为x和y_pred, 使用np.argmax获得预测的索引值
第三步:构建生成卷积过程中参数的函数, tf.Variable(tf.truncate_normal(shape, stddev=0.05))
第四步:构建进行卷积的函数,使用tf.nn.conv2(x, w, stride=[1, 2, 2, 1], padding='SAME'),再加上偏置项b, 使用激活层tf.nn.relu构建, 使用tf.nn.max_pool构建池化层
第五步:构建进行维度变换的函数,用于进行第一次全连接层的卷积到全连接的维度变换,使用image.get_shape()[1:4].num_elements获得后3个维度的个数之和,即乘积
第六步:构造进行全连接的函数,使用tf.matmul构造全连接函数,这里的话,需要使用tf.nn.dropout进行dropout防止过拟合
第七步:开始进行卷积过程
第一步:第一层卷积
第二步:第二层卷积
第三步:第三次卷积
第四步:第一次全连接,使用conv.get_shape[1:4].num_elements获得维度,构造参数
第五步:第二次全连接
第八步:y_pred = tf.nn.softmax构造y_pred, 使用tf.argmax(y_pred, 1)输出索引值
第九步:使用tf.nn.softmax_logits构造损失值loss, logits=score, labels= y_true
第十步:使用tf.train.Adaoptimer().minimize自适应梯度下降降低损失值
第十一步:使用tf.equal(y_pred_cls, y_true_cls) ,tf.reduce_mean构造准确率
第十二步:构建train函数, 开始进行训练,首先使用data.train.next_batch获得batch训练样本,使用sess.run训练trainopt降低损失值,进行参数的训练
第十三步:每一个epoch值,获得train 的batch,获得val_batch,对训练集和验证集的准确率进行展示
代码:train.py
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import dataset from numpy.random import seed seed(0) from tensorflow import set_random_seed set_random_seed(20) image_size = 60
val_size = 0.2
file_path = 'training_data'
classes = ['cats', 'dogs']
num_channel = 3
num_classes = len(classes) # 第一部分数据的载入
data = dataset.read_train_data(file_path, image_size, classes, val_size) image_num = data.train.images.shape[0]
# 第二部分:数据的实际训练 # 第一步参数设置,卷积层的维度和filter的个数
# 第一层卷积大小
filter1_size = 3
filter1_num = 32
# 第二层卷积大小
filter2_size = 3
filter2_num = 32
# 第三层卷积大小
filter3_size = 3
filter3_num = 64
# 隐含层大小
fc1_num = 1024
# 第二步:使用tf.placeholder设置初始输入参数
# 输入参数大小, [图片的数目,图片的宽度, 图片的长度, 图片的通道数]
x = tf.placeholder(tf.float32, [None, image_size, image_size, num_channel], name='x')
# 输入图片标签值,大小为[N, num_classes] 这里为N*2
y_true = tf.placeholder(tf.float32, [None, num_classes], name='y_true')
#真实类别对应的索引值,即1所在的位置
y_true_cls = tf.argmax(y_true, 1) # 第三步:生成卷积过程中所需要的函数
def create_weight(shape):
# 生成正态分布的初始值
return tf.Variable(tf.truncated_normal(shape, stddev=0.05)) def create_bias(size):
# 生成常数分布的初始值
return tf.Variable(tf.constant(0.05, shape=[size]))
# 第四步:构造进行卷积的函数
def create_convolution_layers(input, input_channel, filter_size, filter_num):
# 生成卷积使用的W,[3, 3, 3, 32]第一层卷积核大小
W = create_weight([filter_size, filter_size, input_channel, filter_num])
# 生成偏置项b [32]
b = create_bias(filter_num)
# 进行卷积操作
conv_layer = tf.nn.conv2d(input, W, strides=[1, 1, 1, 1], padding='SAME') + b
# 进行激活操作
conv_layer = tf.nn.relu(conv_layer)
# 使用tf.nn.max_pool进行池化操作
max_pool = tf.nn.max_pool(conv_layer, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 返回池化的结果
return max_pool
# 第五步:构造图像变换的函数
def create_flatten_conv(input):
# 获得图片的后3个维度的大小
input_shape = input.get_shape()[1:4].num_elements()
# 对图像进行维度的变化,即[-1, input_shape] 以便用于后续的全连接操作
out = tf.reshape(input, shape=[-1, input_shape]) return out
# 第六步:构造进行全连接变化的函数
def create_fc_layer(input, num_input, fc1_num, relu_true = True):
# 构造全连接的函数,即后三个维度的大小和第一个全连接的大小
W = create_weight([num_input, fc1_num])
# 构造偏置项b
b = create_bias(fc1_num)
# 构造线性变化,即x * w + b
layer = tf.matmul(input, W) + b
# 对全连接层进行dropout变化
layer = tf.nn.dropout(layer, keep_prob=0.7)
# 如果需要进行激活层
if relu_true:
# 就进行激活变化
layer = tf.nn.relu(layer)
# 返回结果
return layer
# 第七步:进行正式的卷积过程
# 第一层卷积,输入为x, 通道数,卷积核的大小,卷积的个数
conv_h1 = create_convolution_layers(x, num_channel, filter1_size, filter1_num)
# 第二层卷积
conv_h2 = create_convolution_layers(conv_h1, filter1_num, filter2_size, filter2_num)
# 第三层卷积
conv_h3 = create_convolution_layers(conv_h2, filter2_num, filter3_size, filter3_num)
# 获得第三层卷积后的后3个维度的大小
flatten_shape = conv_h3.get_shape()[1:4].num_elements()
# 对图像进行维度变化
flatten_conv = create_flatten_conv(conv_h3)
# 进行全连接操作,输入的是变换后的图像,全连接的第一个维度和第二个维度
fc_h1 = create_fc_layer(flatten_conv, flatten_shape, fc1_num)
# 进行第二次全连接,输出预测的得分值
out = create_fc_layer(fc_h1, fc1_num, num_classes, relu_true=False)
# 第八步:使用tf.nn.softmax获得输入得分的概率值
y_pred = tf.nn.softmax(out, name='y_pred')
# 使用tf.agrmax获得对应的最大索引的大小
y_pred_cls = tf.argmax(y_pred, 1)
# 第九步:使用tf.reduce_mean获得softmax的损失值
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_true, logits=out))
# 第十步:使用自适应梯度下降,进行损失值的下降
train_op = tf.train.AdamOptimizer(0.0001).minimize(cost)
# 第十一步:使用tf.equal表示类别是否相同
correct_pred = tf.equal(y_true_cls, y_pred_cls)
accur = tf.reduce_mean(tf.cast(correct_pred, 'float')) # 构造session函数
session = tf.Session()
# 构造存储函数
saver = tf.train.Saver()
# 进行初始化操作
session.run(tf.global_variables_initializer()) batch_size = 32 def show_progress(data, lost, epoch, i): tr_image_batch, tr_label_batch = data.train.next_batch(batch_size)[0:2]
val_image_batch, val_label_batch = data.val.next_batch(batch_size)[0:2]
# 输出训练样本的准确率
tr_accur = session.run(accur, feed_dict={x:tr_image_batch, y_true:tr_label_batch})
# 输出验证样本的准确率
val_accur = session.run(accur, feed_dict={x:val_image_batch, y_true:val_label_batch})
# 打印epoch值,训练集和验证集准确率,训练的损失值,迭代的次数
content = ('train_epoch {0} tr_accur {1:>6.1%} val_accur {2:6.1%} train_loss {3:.3f} iteration_num {4}')
print(content.format(epoch, tr_accur, val_accur, lost, i))
def train(num_iteration):
start_epoch = 0
for i in range(num_iteration):
# 第十二步:构造函数进行参数的实际代入,使用data.train.next_batch获得模型的训练样本和验证集样本,进行模型训练
batch_image, batch_labels, batch_nams, batch_cls = data.train.next_batch(batch_size)
session.run(train_op, feed_dict={x:batch_image, y_true:batch_labels})
#第十三步:每一个epoch进行模型的准确率的输出
if i % int(data.train.num_image / batch_size) == 0:
# 计算模型的损失值
loss = session.run(cost, feed_dict={x:batch_image, y_true:batch_labels})
# 展示模型的训练集和验证集的准确率
show_progress(data, loss, start_epoch, i)
start_epoch += 1
# 第十四步:使用saver.save(session, './dog-cats-model/dog-cat.ckpt', global_step)进行模型的参数保存
saver.save(session, './dog-cats-model/dog-cat.ckpt', global_step=i) train(8000)
第三部分:进行模型的预测
第一步:图片的输入,对于输入的图片需要进行与训练样本输入时相同的处理
第一步:使用cv2.imread()进行样本的读取
第二步:使用cv2.resize进行图片的维度变换
第三步:.astype对样本的类型进行变换
第四步:使用np.multipy对样本进行归一化操作
第五步:将图片的维度进行变换,因为是一张图片,维度变化为[1, 60, 60, 3]
第二步:将训练好的模型进行加载
第一步:构建sess = tf.Session()
第二步:使用saver = tf.train.import_meta_graph 加载模型的meta
第三步:使用saver.restore() 加载模型的ckpt-3750
第四步:graph = tf.get_default_graph()获得参数结构图
第五步:使用graph.get_tensor_by_name('y_pred:0') 获得预测y_pred
第五步:使用graph.get_tensor_by_name('x:0') 获得输入x
第六步:使用graph.get_tensor_by_name('y_pred:0') 获得输入标签y_true
第七步:使用np.zeros((1, 2))构造输入值得标签
第八步:使用sess.run(y_pred, feed_dict={x:x_batch, y_pred:y_test_img}) 进行结果的预测
第九步:使用tf.argmax获得标签的索引,使用标签名获得最终的预测结果
代码:predict.py
import tensorflow as tf
import numpy as np
import cv2 # 第一步图片的载入
image_size = 60
# 图片的文件名
path = 'cat.4.jpg'
# 读取图片
image = cv2.imread(path)
# 改变图片的大小
image = cv2.resize(image, (image_size, image_size), 0, 0, cv2.INTER_LINEAR)
# 图片类型的转换
image = image.astype('float32')
# 进行图像的归一化
image = np.multiply(image, 1.0/255.0)
# 对图像进行维度的变化
x_batch = image.reshape(1, image_size, image_size, 3) # 加载模型,对图片进行预测
# 初始化sess
sess = tf.Session()
# 载入saver,获得模型的结果saver
saver = tf.train.import_meta_graph('./dog-cats-model/dog-cat.ckpt-3700.meta')
# 使用saver加载sess
saver.restore(sess, './dog-cats-model/dog-cat.ckpt-3700')
# 获得模型的结构图
graph = tf.get_default_graph()
# 使用结构图获得模型参数y_pred
y_pred = graph.get_tensor_by_name('y_pred:0')
# 获得模型参数x
x = graph.get_tensor_by_name('x:0')
# 获得模型参数y_true
y_true = graph.get_tensor_by_name('y_true:0')
# 构造真实的标签值,初始化
y_test_images = np.zeros((1, 2))
# 输入的样本参数
feed_dict_testing = {x:x_batch, y_pred:y_test_images}
# 获得模型的预测结果,使用sess.run
result = sess.run(y_pred, feed_dict=feed_dict_testing)
# 根据预测得分,获得最大值的标签索引做为标签索引,获得最终的预测结果
res_label = ['cat', 'dog']
print(res_label[result.argmax()])
深度学习原理与框架-猫狗图像识别-卷积神经网络(代码) 1.cv2.resize(图片压缩) 2..get_shape()[1:4].num_elements(获得最后三维度之和) 3.saver.save(训练参数的保存) 4.tf.train.import_meta_graph(加载模型结构) 5.saver.restore(训练参数载入)的更多相关文章
-
深度学习原理与框架-CNN在文本分类的应用 1.tf.nn.embedding_lookup(根据索引数据从数据中取出数据) 2.saver.restore(加载sess参数)
1. tf.nn.embedding_lookup(W, X) W的维度为[len(vocabulary_list), 128], X的维度为[?, 8],组合后的维度为[?, 8, 128] 代码说 ...
-
深度学习原理与框架-Alexnet(迁移学习代码) 1.sys.argv[1:](控制台输入的参数获取第二个参数开始) 2.tf.split(对数据进行切分操作) 3.tf.concat(对数据进行合并操作) 4.tf.variable_scope(指定w的使用范围) 5.tf.get_variable(构造和获得参数) 6.np.load(加载.npy文件)
1. sys.argv[1:] # 在控制台进行参数的输入时,只使用第二个参数以后的数据 参数说明:控制台的输入:python test.py what, 使用sys.argv[1:],那么将获得w ...
-
深度学习原理与框架-图像补全(原理与代码) 1.tf.nn.moments(求平均值和标准差) 2.tf.control_dependencies(先执行内部操作) 3.tf.cond(判别执行前或后函数) 4.tf.nn.atrous_conv2d 5.tf.nn.conv2d_transpose(反卷积) 7.tf.train.get_checkpoint_state(判断sess是否存在
1. tf.nn.moments(x, axes=[0, 1, 2]) # 对前三个维度求平均值和标准差,结果为最后一个维度,即对每个feature_map求平均值和标准差 参数说明:x为输入的fe ...
-
深度学习原理与框架-Tfrecord数据集的读取与训练(代码) 1.tf.train.batch(获取batch图片) 2.tf.image.resize_image_with_crop_or_pad(图片压缩) 3.tf.train.per_image_stand..(图片标准化) 4.tf.train.string_input_producer(字符串入队列) 5.tf.TFRecord(读
1.tf.train.batch(image, batch_size=batch_size, num_threads=1) # 获取一个batch的数据 参数说明:image表示输入图片,batch_ ...
-
深度学习原理与框架-Tfrecord数据集的制作 1.tf.train.Examples(数据转换为二进制) 3.tf.image.encode_jpeg(解码图片加码成jpeg) 4.tf.train.Coordinator(构建多线程通道) 5.threading.Thread(建立单线程) 6.tf.python_io.TFR(TFR读入器)
1. 配套使用: tf.train.Examples将数据转换为二进制,提升IO效率和方便管理 对于int类型 : tf.train.Examples(features=tf.train.Featur ...
-
深度学习原理与框架-卷积神经网络-cifar10分类(图片分类代码) 1.数据读入 2.模型构建 3.模型参数训练
卷积神经网络:下面要说的这个网络,由下面三层所组成 卷积网络:卷积层 + 激活层relu+ 池化层max_pool组成 神经网络:线性变化 + 激活层relu 神经网络: 线性变化(获得得分值) 代码 ...
-
深度学习原理与框架-Tensorflow基本操作-mnist数据集的逻辑回归 1.tf.matmul(点乘操作) 2.tf.equal(对应位置是否相等) 3.tf.cast(将布尔类型转换为数值类型) 4.tf.argmax(返回最大值的索引) 5.tf.nn.softmax(计算softmax概率值) 6.tf.train.GradientDescentOptimizer(损失值梯度下降器)
1. tf.matmul(X, w) # 进行点乘操作 参数说明:X,w都表示输入的数据, 2.tf.equal(x, y) # 比较两个数据对应位置的数是否相等,返回值为True,或者False 参 ...
-
深度学习原理与框架-递归神经网络-时间序列预测(代码) 1.csv.reader(进行csv文件的读取) 2.X.tolist(将数据转换为列表类型)
1. csv.reader(csvfile) # 进行csv文件的读取操作 参数说明:csvfile表示已经有with oepn 打开的文件 2. X.tolist() 将数据转换为列表类型 参数说明 ...
-
深度学习原理与框架-递归神经网络-RNN_exmaple(代码) 1.rnn.BasicLSTMCell(构造基本网络) 2.tf.nn.dynamic_rnn(执行rnn网络) 3.tf.expand_dim(增加输入数据的维度) 4.tf.tile(在某个维度上按照倍数进行平铺迭代) 5.tf.squeeze(去除维度上为1的维度)
1. rnn.BasicLSTMCell(num_hidden) # 构造单层的lstm网络结构 参数说明:num_hidden表示隐藏层的个数 2.tf.nn.dynamic_rnn(cell, ...
随机推荐
-
JS操作Json
因为我水啊 所以我就要手打一下 熟悉一下 ===== JSON 全称 JavaScript Object Notation(标记) 一种轻量级的数据交互格式,采用完全独立于语言的文本格式 同事JSON ...
-
萌新笔记——C++里创建 Trie字典树(中文词典)(一)(插入、遍历)
萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...
-
[Zigbee]定时器1
注意:在定时器可以使用一个输入/输出引脚之前,所需的 I/O 引脚必须配置为定时器 1 的外设引脚. 定时器1的引脚映射方案选用是备用2方案:P07对应通道3.P06-通道4.P12-通道0.P11- ...
-
Win7激活工具|OEM小马激活
OEM小马激活,Win7激活. 免费下载:http://yunpan.cn/cmZ5DyDvXG2In 访问密码 7fcf
-
【转载】MFC 程序入口和执行流程
原文链接: http://www.cnblogs.com/liuweilinlin/archive/2012/08/16/2643272.html 一 MFC程序执行过程剖析 1)我们知道在WIN32 ...
-
css3 动画demo
1)http://www.yyyweb.com/demo/css-cokecan/inner.html 2)页面切换效果demo http://www.yyyweb.com/demo/page-tra ...
-
如何使用VSTS做压力测试
1 前言 1.1 目的 本文档主要介绍如何在VSTS环境中进行LoadTest测试,给测试人员和初次使用者提供参考. 对该工具进行LoadTest测试的优劣进行简单的分析说明. 1.2 软件版本 本文 ...
-
MFC: 获得关机消息;阻止Windows关机
WM_QUERYENDSESSION消息是Windows向你询问Windows能否关闭,WM_ENDSESSION消息表示提示你Windows即将关闭.故当应用程序退出时, WM_QUERYENDSE ...
-
ios屏幕怎么投屏到电脑显示器
iphone在国内一直都很受欢迎,为什么这么受欢迎呢?其实苹果手机操作系统非常的新颖,让人对手机有了重新的认识.但是ios屏幕怎么投屏到电脑显示器.感兴趣的一起阅读下面的内容吧! 使用工具: 苹果手机 ...
-
《图解HTTP》读书笔记(一:网络基础TCP/IP)
好书什么时候开始读都不晚.作为一个测试人员,是一定要掌握一些网络的基础知识的.希望能够边读书边在这里记录笔记,便于加深理解以及日后查阅. 一.TCP/IP协议族 计算机与网络设备要互相通信,双方必须基 ...