当前位置: 首页 > 编程日记 > 正文

深度有趣 | 27 服饰关键点定位

简介

介绍如何使用CPM(Convolutional Pose Machines)实现服饰关键点定位

原理

关键点定位是一类常见而有用的任务,某种意义上可以理解为一种特征工程

  • 人脸关键点定位,可用于人脸识别、表情识别
  • 人体骨骼关键点定位,可用于姿态估计
  • 手部关键点定位,可用于手势识别

输入是一张图片,输出是每个关键点的x、y坐标,一般会归一化到0~1区间中,所以可以理解为回归问题

但是直接对坐标值进行回归会导致较大误差,更好的做法是输出一个低分辨率的热图,使得关键点所在位置输出较高响应,而其他位置则输出较低响应

CPM(Convolutional Pose Machines)的基本思想是使用多个级联的stage,每个stage包含多个CNN并且都输出热图

通过最小化每个stage的热图和ground truth之间的差距,从而得到越来越准确的关键点定位结果

数据

使用天池FashionAI全球挑战赛提供的数据,fashionai.alibaba.com/

其中服饰关键点定位赛题提供的训练集包括4W多张图片,测试集包括将近1W张图片

每张图片都指定了对应的服饰类别,共5类:上衣(blouse)、外套(outwear)、连身裙(dress)、半身裙(skirt)、裤子(trousers)

训练集还提供了每张图片对应的24个关键点的标注,包括x坐标、y坐标、是否可见三项信息,但并不是每类服饰都有24个关键点

关于以上数据的更多介绍可以参考以下文章,zhuanlan.zhihu.com/p/34928763

为了简化问题,以下仅使用dress类别的训练集数据训练CPM模型

实现

加载库

# -*- coding: utf-8 -*-import tensorflow as tf
import numpy as np
import pandas as pd
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split
import cv2
import matplotlib.pyplot as plt
%matplotlib inline
from imageio import imread, imsave
import os
import glob
from tqdm import tqdm
import warnings
warnings.filterwarnings('ignore')
复制代码

加载训练集和测试集

train = pd.read_csv(os.path.join('data', 'train', 'train.csv'))
train_warm = pd.read_csv(os.path.join('data', 'train_warm', 'train_warm.csv'))
test = pd.read_csv(os.path.join('data', 'test', 'test.csv'))
print(len(train), len(train_warm), len(test))columns = train.columns
print(len(columns), columns)train['image_id'] = train['image_id'].apply(lambda x:os.path.join('train', x))
train_warm['image_id'] = train_warm['image_id'].apply(lambda x:os.path.join('train_warm', x))
train = pd.concat([train, train_warm])
del train_warm
train.head()
复制代码

仅保留dress类别的数据

train = train[train.image_category == 'dress']
test = test[test.image_category == 'dress']
print(len(train), len(test))
复制代码

拆分标注信息中的x坐标、y坐标、是否可见

for col in columns:if col in ['image_id', 'image_category']:continuetrain[col + '_x'] = train[col].apply(lambda x:float(x.split('_')[0]))train[col + '_y'] = train[col].apply(lambda x:float(x.split('_')[1]))train[col + '_s'] = train[col].apply(lambda x:float(x.split('_')[2]))train.drop([col], axis=1, inplace=True)
train.head()
复制代码

将x坐标和y坐标进行归一化

features = ['neckline_left', 'neckline_right', 'center_front', 'shoulder_left', 'shoulder_right', 'armpit_left', 'armpit_right', 'waistline_left', 'waistline_right', 'cuff_left_in', 'cuff_left_out', 'cuff_right_in', 'cuff_right_out', 'hemline_left', 'hemline_right']train = train.to_dict('records')
for i in tqdm(range(len(train))):record = train[i]img = imread(os.path.join('data', record['image_id']))h = img.shape[0]w = img.shape[1]for col in features:if record[col + '_s'] >= 0:train[i][col + '_x'] /= wtrain[i][col + '_y'] /= helse:train[i][col + '_x'] = 0train[i][col + '_y'] = 0
复制代码

随机选一些训练数据并绘图查看

img_size = 256
r = 10
c = 10
puzzle = np.ones((img_size * r, img_size * c, 3))
random_indexs = np.random.choice(len(train), 100)
for i in range(100):record = train[random_indexs[i]]img = imread(os.path.join('data', record['image_id']))img = cv2.resize(img, (img_size, img_size))for col in features:if record[col + '_s'] >= 0:cv2.circle(img, (int(img_size * record[col + '_x']), int(img_size * record[col + '_y'])), 3, (120, 240, 120), 2)img = img / 255.r = i // 10c = i % 10puzzle[r * img_size: (r + 1) * img_size, c * img_size: (c + 1) * img_size, :] = img
plt.figure(figsize=(15, 15))
plt.imshow(puzzle)
plt.show()
复制代码

整理数据并分割训练集和验证集

X_train = []
Y_train = []
for i in tqdm(range(len(train))):record = train[i]img = imread(os.path.join('data', record['image_id']))img = cv2.resize(img, (img_size, img_size))y = []for col in features:y.append([record[col + '_x'], record[col + '_y']])X_train.append(img)Y_train.append(y)X_train = np.array(X_train)
Y_train = np.array(Y_train)
print(X_train.shape)
print(Y_train.shape)X_train, X_valid, Y_train, Y_valid = train_test_split(X_train, Y_train, test_size=0.1)
print(X_train.shape, Y_train.shape)
print(X_valid.shape, Y_valid.shape)
复制代码

定义一些参数和模型输入

batch_size = 16
heatmap_size = 32
stages = 6
y_dim = Y_train.shape[1]X = tf.placeholder(tf.float32, [None, img_size, img_size, 3], name='X')
Y = tf.placeholder(tf.float32, [None, heatmap_size, heatmap_size, y_dim + 1], name='Y')def conv2d(inputs, filters, kernel_size, padding='same', activation=tf.nn.relu, name=''):if name:return tf.layers.conv2d(inputs, filters=filters, kernel_size=kernel_size, strides=1, padding=padding, activation=activation, name=name, kernel_initializer=tf.contrib.layers.xavier_initializer())else:return tf.layers.conv2d(inputs, filters=filters, kernel_size=kernel_size, strides=1, padding=padding, activation=activation, kernel_initializer=tf.contrib.layers.xavier_initializer())def maxpool2d(inputs):return tf.layers.max_pooling2d(inputs, pool_size=2, strides=2, padding='valid')
复制代码

定义CPM模型,使用6个stage

stage_heatmaps = []# sub_stage
h0 = maxpool2d(conv2d(conv2d(X, 64, 3), 64, 3))
h0 = maxpool2d(conv2d(conv2d(h0, 128, 3), 128, 3))
h0 = maxpool2d(conv2d(conv2d(conv2d(conv2d(h0, 256, 3), 256, 3), 256, 3), 256, 3))
for i in range(6):h0 = conv2d(h0, 512, 3)
sub_stage = conv2d(h0, 128, 3) # batch_size, 32, 32, 128# stage_1
h0 = conv2d(sub_stage, 512, 1, padding='valid')
h0 = conv2d(h0, y_dim + 1, 1, padding='valid', activation=None, name='stage_1')
stage_heatmaps.append(h0)# other stages
for stage in range(2, stages + 1):h0 = tf.concat([stage_heatmaps[-1], sub_stage], axis=3)for i in range(5):h0 = conv2d(h0, 128, 7)h0 = conv2d(h0, 128, 1, padding='valid')h0 = conv2d(h0, y_dim + 1, 1, padding='valid', activation=None, name='stage_%d' % stage)stage_heatmaps.append(h0)
复制代码

定义损失函数和优化器

global_step = tf.Variable(0, trainable=False)
learning_rate = tf.train.exponential_decay(0.001, global_step=global_step, decay_steps=1000, decay_rate=0.9)losses = [0 for _ in range(stages)]
total_loss = 0
for stage in range(stages):losses[stage] = tf.losses.mean_squared_error(Y, stage_heatmaps[stage])total_loss += losses[stage]total_loss_with_reg = total_loss + tf.contrib.layers.apply_regularization(tf.contrib.layers.l2_regularizer(1e-10), tf.trainable_variables())
total_loss = total_loss / stages
total_loss_with_reg = total_loss_with_reg / stagesoptimizer = tf.contrib.layers.optimize_loss(total_loss_with_reg, global_step=global_step, learning_rate=learning_rate, optimizer='Adam', increment_global_step=True)
复制代码

由于训练数据较少,因此定义一个数据增强的函数

def transform(X_batch, Y_batch):X_data = []Y_data = []offset = 20for i in range(X_batch.shape[0]):img = X_batch[i]# random rotationdegree = int(np.random.random() * offset - offset / 2)rad = degree / 180 * np.pimat = cv2.getRotationMatrix2D((img_size / 2, img_size / 2), degree, 1)img_ = cv2.warpAffine(img, mat, (img_size, img_size), borderValue=(255, 255, 255))# random translationx0 = int(np.random.random() * offset - offset / 2)y0 = int(np.random.random() * offset - offset / 2)mat = np.float32([[1, 0, x0], [0, 1, y0]])img_ = cv2.warpAffine(img_, mat, (img_size, img_size), borderValue=(255, 255, 255))# random flipif np.random.random() > 0.5:img_ = np.fliplr(img_)flip = Trueelse:flip = FalseX_data.append(img_)points = []for j in range(y_dim):x = Y_batch[i, j, 0] * img_sizey = Y_batch[i, j, 1] * img_size# random rotationdx = x - img_size / 2  dy = y - img_size / 2x = int(dx * np.cos(rad) + dy * np.sin(rad) + img_size / 2)  y = int(-dx * np.sin(rad) + dy * np.cos(rad) + img_size / 2)# random translationx += x0y += y0x = x / img_sizey = y / img_sizepoints.append([x, y])# random flipif flip:data = {features[j]: points[j] for j in range(y_dim)}points = []for j in range(y_dim):col = features[j]if col.find('left') >= 0:col = col.replace('left', 'right')elif col.find('right') >= 0:col = col.replace('right', 'left')[x, y] = data[col]x = 1 - xpoints.append([x, y])Y_data.append(points)X_data = np.array(X_data)Y_data = np.array(Y_data)# preprocessX_data = (X_data / 255. - 0.5) * 2Y_heatmap = []for i in range(Y_data.shape[0]):heatmaps = []invert_heatmap = np.ones((heatmap_size, heatmap_size))for j in range(Y_data.shape[1]):x0 = int(Y_data[i, j, 0] * heatmap_size)y0 = int(Y_data[i, j, 1] * heatmap_size)x = np.arange(0, heatmap_size, 1, float)y = x[:, np.newaxis]cur_heatmap = np.exp(-((x - x0) ** 2 + (y - y0) ** 2) / (2.0 * 1.0 ** 2))heatmaps.append(cur_heatmap)invert_heatmap -= cur_heatmapheatmaps.append(invert_heatmap)Y_heatmap.append(heatmaps)Y_heatmap = np.array(Y_heatmap)Y_heatmap = np.transpose(Y_heatmap, (0, 2, 3, 1)) # batch_size, heatmap_size, heatmap_size, y_dim + 1return X_data, Y_data, Y_heatmap
复制代码

查看数据增强之后的图片和关键点是否正确

X_batch = X_train[:batch_size]
Y_batch = Y_train[:batch_size]
X_data, Y_data, Y_heatmap = transform(X_batch, Y_batch)n = int(np.sqrt(batch_size))
puzzle = np.ones((img_size * n, img_size * n, 3))
for i in range(batch_size):img = (X_data[i] + 1) / 2for j in range(y_dim):cv2.circle(img, (int(img_size * Y_data[i, j, 0]), int(img_size * Y_data[i, j, 1])), 3, (120, 240, 120), 2)r = i // nc = i % npuzzle[r * img_size: (r + 1) * img_size, c * img_size: (c + 1) * img_size, :] = img
plt.figure(figsize=(12, 12))
plt.imshow(puzzle)
plt.show()
复制代码

可以看到,在经过随机旋转、随机平移、随机水平翻转之后,图片和关键点依旧一一对应

训练模型,使用early stopping

sess = tf.Session()
sess.run(tf.global_variables_initializer())OUTPUT_DIR = 'samples'
if not os.path.exists(OUTPUT_DIR):os.mkdir(OUTPUT_DIR)for stage in range(stages):tf.summary.scalar('loss/loss_stage_%d' % (stage + 1), losses[stage])
tf.summary.scalar('loss/total_loss', total_loss)
summary = tf.summary.merge_all()
writer = tf.summary.FileWriter(OUTPUT_DIR)loss_valid_min = np.inf
saver = tf.train.Saver()epochs = 100
patience = 10
for e in range(epochs):loss_train = []loss_valid = []X_train, Y_train = shuffle(X_train, Y_train)for i in tqdm(range(X_train.shape[0] // batch_size)):X_batch = X_train[i * batch_size: (i + 1) * batch_size, :, :, :]Y_batch = Y_train[i * batch_size: (i + 1) * batch_size, :, :]X_data, Y_data, Y_heatmap = transform(X_batch, Y_batch)_, ls, lr, stage_heatmaps_ = sess.run([optimizer, total_loss, learning_rate, stage_heatmaps], feed_dict={X: X_data, Y: Y_heatmap})loss_train.append(ls)if i > 0 and i % 100 == 0:writer.add_summary(sess.run(summary, feed_dict={X: X_data, Y: Y_heatmap}), e * X_train.shape[0] // batch_size + i)writer.flush()loss_train = np.mean(loss_train)demo_img = (X_data[0] + 1) / 2demo_heatmaps = []for stage in range(stages):demo_heatmap = stage_heatmaps_[stage][0, :, :, :y_dim].reshape((heatmap_size, heatmap_size, y_dim))demo_heatmap = cv2.resize(demo_heatmap, (img_size, img_size))demo_heatmap = np.amax(demo_heatmap, axis=2)demo_heatmap = np.reshape(demo_heatmap, (img_size, img_size, 1))demo_heatmap = np.repeat(demo_heatmap, 3, axis=2)demo_heatmaps.append(demo_heatmap)demo_gt_heatmap = Y_heatmap[0, :, :, :y_dim].reshape((heatmap_size, heatmap_size, y_dim))demo_gt_heatmap = cv2.resize(demo_gt_heatmap, (img_size, img_size))demo_gt_heatmap = np.amax(demo_gt_heatmap, axis=2)demo_gt_heatmap = np.reshape(demo_gt_heatmap, (img_size, img_size, 1))demo_gt_heatmap = np.repeat(demo_gt_heatmap, 3, axis=2)upper_img = np.concatenate((demo_heatmaps[0], demo_heatmaps[1], demo_heatmaps[2]), axis=1)blend_img = 0.5 * demo_img + 0.5 * demo_gt_heatmaplower_img = np.concatenate((demo_heatmaps[-1], demo_gt_heatmap, blend_img), axis=1)demo_img = np.concatenate((upper_img, lower_img), axis=0)imsave(os.path.join(OUTPUT_DIR, 'sample_%d.jpg' % e), demo_img)X_valid, Y_valid = shuffle(X_valid, Y_valid)for i in range(X_valid.shape[0] // batch_size):X_batch = X_valid[i * batch_size: (i + 1) * batch_size, :, :, :]Y_batch = Y_valid[i * batch_size: (i + 1) * batch_size, :, :]X_data, Y_data, Y_heatmap = transform(X_batch, Y_batch)ls = sess.run(total_loss, feed_dict={X: X_data, Y: Y_heatmap})loss_valid.append(ls)loss_valid = np.mean(loss_valid)print('Epoch %d, lr %.6f, train loss %.6f, valid loss %.6f' % (e, lr, loss_train, loss_valid))if loss_valid < loss_valid_min:print('Saving model...')saver.save(sess, os.path.join(OUTPUT_DIR, 'cpm'))loss_valid_min = loss_validpatience = 10else:patience -= 1if patience == 0:break
复制代码

经过87个epoch之后训练提前停止,训练集损失为0.001228,验证集损失为0.001871,验证集最低损失为0.001821

训练集结果如下,上面三张图依次为stage1、stage2、stage3的结果,下面三张图依次为stage6、ground truth、groud truth和原图

在本机上使用以下代码,对测试集中的图片进行关键点定位

# -*- coding: utf-8 -*-import tensorflow as tf
import numpy as np
import pandas as pd
from sklearn.utils import shuffle
import cv2
import matplotlib.pyplot as plt
from imageio import imread, imsave
import ostest = pd.read_csv(os.path.join('data', 'test', 'test.csv'))
test['image_id'] = test['image_id'].apply(lambda x:os.path.join('test', x))
test = test[test.image_category == 'dress']
test = test['image_id'].valuesbatch_size = 16
img_size = 256
test = shuffle(test)
test = test[:batch_size]
X_test = []
for i in range(batch_size):img = imread(os.path.join('data', test[i]))img = cv2.resize(img, (img_size, img_size))X_test.append(img)
X_test = np.array(X_test)
print(X_test.shape)sess = tf.Session()
sess.run(tf.global_variables_initializer())OUTPUT_DIR = 'samples'
saver = tf.train.import_meta_graph(os.path.join(OUTPUT_DIR, 'cpm.meta'))
saver.restore(sess, tf.train.latest_checkpoint(OUTPUT_DIR))stages = 6
y_dim = 15
heatmap_size = 32
graph = tf.get_default_graph()
X = graph.get_tensor_by_name('X:0')
stage_heatmap = graph.get_tensor_by_name('stage_%d/BiasAdd:0' % stages)def visualize_result(imgs, heatmap, joints):imgs = imgs.astype(np.int32)coords = []for i in range(imgs.shape[0]):hp = heatmap[i, :, :, :joints].reshape((heatmap_size, heatmap_size, joints))hp = cv2.resize(hp, (img_size, img_size))coord = np.zeros((joints, 2))for j in range(joints):xy = np.unravel_index(np.argmax(hp[:, :, j]), (img_size, img_size))coord[j, :] = [xy[0], xy[1]]cv2.circle(imgs[i], (xy[1], xy[0]), 3, (120, 240, 120), 2)coords.append(coord)return imgs / 255., coordsheatmap = sess.run(stage_heatmap, feed_dict={X: (X_test / 255. - 0.5) * 2})
X_test, coords = visualize_result(X_test, heatmap, y_dim) n = int(np.sqrt(batch_size))
puzzle = np.ones((img_size * n, img_size * n, 3))
for i in range(batch_size):img = X_test[i]r = i // nc = i % npuzzle[r * img_size: (r + 1) * img_size, c * img_size: (c + 1) * img_size, :] = img
plt.figure(figsize=(12, 12))
plt.imshow(puzzle)
plt.show()
imsave('服饰关键点定位测试集结果.jpg', puzzle)
复制代码

测试集结果如下,对于大多数情况能够得到很准确的关键点定位结果

参考

  • Convolutional Pose Machines:arxiv.org/abs/1602.00…
  • Code repository for Convolutional Pose Machines:github.com/shihenw/con…
  • 天池FashionAI全球挑战赛小小尝试:zhuanlan.zhihu.com/p/34928763

视频讲解课程

深度有趣(一)

相关文章:

有答案了!一张图告诉你到底学Python还是Java!你咋看?

2019年&#xff0c;该学Java还是Python&#xff1f;不&#xff0c;实际上应该这样问&#xff1a;都9102年了&#xff0c;难道有谁不想成为Python程序员吗&#xff1f;作为“常青树大佬”Java 和“新晋大佬”Python &#xff0c;经常被人拿来对比&#xff0c;对于刚开始起步学习…

图像二值化----otsu(最大类间方差法、大津算法)(二)

转自&#xff1a;http://blog.stevenwang.name/ostu-threshold-56002.html OTSU算法也称最大类间差法&#xff0c;有时也称之为大津算法&#xff0c;被认为是图像分割中阈值选取的最佳算法&#xff0c;计算简单&#xff0c;不受图像亮度和对比度的影响&#xff0c;因此在数字图…

android同时使用多个library时的问题

剧情是这样&#xff0c;我的app要使用两个library&#xff0c;如&#xff1a;LibraryA&#xff0c;LibraryB。这两个库又都需要support.v4.jar。 由于加载的时间不同&#xff0c;所以两个support.v4.jar不同&#xff0c;出错的提示如下&#xff1a; [2012-09-28 16:37:22 - ] F…

C#版 - Leetcode49 - 字母异位词分组 - 题解

C#版 - Leetcode49 - 字母异位词分组 - 题解 Leetcode49.Group Anagrams 在线提交:https://leetcode.com/problems/group-anagrams/ 题目描述 给定一个字符串数组&#xff0c;将字母异位词组合在一起。字母异位词指字母相同&#xff0c;但排列不同的字符串。 示例: 输入: [&quo…

来学习几个简单的Hive函数吧!

作者 | 石晓文转载自小小挖掘机&#xff08;ID:wAIsjwj&#xff09;咳咳&#xff0c;今天来介绍一下几个Hive函数吧&#xff0c;先放一张我登哥划水的照片&#xff0c;希望大家也做一只自由的鱼儿&#xff0c;在知识的海洋里游呀游&#xff0c;嘻嘻&#xff01;今天我们来介绍几…

OpenCV编程案例:使用轮廓函数检测连通区域

转自&#xff1a;http://www.aiseminar.cn/bbs/thread-617-1-1.html 此案例位于CXCORE中cvDrawContours函数介绍部分给出。此程序首先载入一个二值图像文件&#xff0c;然后使用函数再次二值化确认。接着使用cvFindContours找到轮廓&#xff0c;然后使用填充方式绘制轮廓线内部…

[译]Web Inspector开始支持CSS区域

最近,开发人员和设计师们可以在WebKit中尝试使用CSS区域特性了,我们认为是时候给他们一些开发工具了.最新版本的Chrome Canary中的web inspector现在已经支持下面这些功能: 查找文档中所有的命名流.显示每个命名流的内容和区域链.高亮页面中的CSS区域,就像是把鼠标放在web insp…

这或许是东半球分析十大排序算法最好的一篇文章

作者 | 不该相遇在秋天转载自五分钟学算法&#xff08;ID:CXYxiaowu&#xff09;前言本文全长 14237 字&#xff0c;配有 70 张图片和动画&#xff0c;和你一起一步步看懂排序算法的运行过程。预计阅读时间 47 分钟&#xff0c;强烈建议先收藏然后通过电脑端进行阅读。No.1 冒泡…

opencv使用cvFindContours提取联通域

转自&#xff1a;http://hi.baidu.com/irmosgarden/blog/item/8ce0174c54b307fad72afcbc.html // m_imgFeature为黑白目标图像&#xff0c;白色为前景&#xff0c;黑色为背景 // 注意此函数会修改m_imgFeature内容。若其不可更改&#xff0c;应另建立副本 // 1. count contou…

朱晔的互联网架构实践心得S1E9:架构评审一百问和设计文档五要素

朱晔的互联网架构实践心得S1E9&#xff1a;架构评审一百问和设计文档五要素 【下载文本PDF进行阅读】 本文我会来说说我认为架构评审中应该看的一些点&#xff0c;以及我写设计文档的一些心得。助你在架构评审中过五关斩六将&#xff0c;助你写出能让人收藏点赞的设计文档。 技…

Mail Archiving Expert电子邮件归档专家

概况作为企业往来最通用的交流工具&#xff0c;企业中有95%以上的文件都是通过邮件来传递与沟通&#xff0c;但是一旦当邮件服务罢工&#xff0c;影响的不仅仅是企业信息交流无法正确与及时的传达&#xff0c;更可能影响企业与客户之间的交易&#xff0c;其后果更是不堪设想&am…

C++中MessageBox的常见用法

转自&#xff1a;http://blog.csdn.net/qiumingbo/archive/2007/05/25/1625324.aspxMessageBox用法消息框是个很常用的控件&#xff0c;属性比较多&#xff0c;本文列出了它的一些常用方法&#xff0c;及指出了它的一些应用场合。1.MessageBox("这是一个最简单的消息框&am…

对标Mobileye!百度Apollo公布L4级自动驾驶纯视觉解决方案Apollo Lite

美国当地时间6月16日-20日&#xff0c;全球计算机视觉及模式识别领域顶级学术会议CVPR 2019&#xff08;Conference on Computer Vision and Pattern Recognition&#xff09;于美国长滩召开。百度Apollo在CVPR 2019公开了自动驾驶纯视觉城市道路闭环解决方案--百度Apollo Lite…

后台服务项目的白盒测试之旅

本文来自阿网易云社区作者&#xff1a;孙婷婷白盒测试起因17年下半年我开始介入部门新项目的服务v2版本的功能测试。刚接手项目时&#xff0c;感到十分头疼&#xff0c;首先它不像我刚接触测试时做的to C端项目&#xff0c;主要是页面展示操作&#xff0c;黑盒测试足够&#xf…

【自然框架 NatureFW】里的两种“映射”方式

自然框架里面采用了两种映射关系&#xff0c;一个是流行的ORM&#xff0c;另一是非主流的“CCM ” &#xff08;我自己想的&#xff0c;呵呵&#xff09;。 先说一下ORM。ORM是O和R的映射关系。也看到很多人写关于ORM的文章&#xff0c;发现好像有个误区。这个误区就是&#x…

ordfilt2函数功能说明

转自&#xff1a;http://www.ilovematlab.cn/thread-91331-1-1.html ordfilt2函数在MATLAB图像处理工具箱中提供了二维统计顺序滤波函数ordfilt2函数。二维统计顺序滤波是中值滤波的推广&#xff0c;对于给定的n个数值&#xff5b;al ,a2,...,an&#xff5d;&#xff0c;将它们…

今晚直播写代码|英伟达工程师亲授如何加速YOLO目标检测

NVIDIA TensorRT是一种高性能深度学习推理优化器和运行时加速库&#xff0c;可以为深度学习推理应用程序提供低延时和高吞吐量。通过TensorRT&#xff0c;开发者可以优化神经网络模型&#xff0c;以高精度校对低精度&#xff0c;最后将模型部署到超大规模数据中心、嵌入式平台或…

TensorFlow Lite:TensorFlow在移动设备与嵌入式设备上的轻量级跨平台解决方案 | Google 开发者大会 2018...

Google 开发者大会 (Google Developer Days&#xff0c;简称 GDD) 是展示 Google 最新开发者产品和平台的全球盛会&#xff0c;旨在帮助你快速开发优质应用&#xff0c;发展和留住活跃用户群&#xff0c;充分利用各种工具获得更多收益。2018 Google 开发者大会于 9 月 20 日和 …

热烈庆祝“mysql 集群数据库架构成功”

坚持了两周&#xff0c;终于在linux下把mysql集群数据库给架起来了&#xff01;下面简单说明下集群数据库原理 第一&#xff1a;集群数据库分MGM,NDBD,SQL 其中MGM是相当于“中央政府”&#xff0c;维持NDBD&#xff0c;SQL等服务器的之间的关系的 NDBD是数据存储的分布化&…

352万帧标注图片,1400个视频,亮风台推最大单目标跟踪数据集

CVPR 2019期间&#xff0c;专注于AR技术&#xff0c;整合软硬件的人工智能公司亮风台公开大规模单目标跟踪高质量数据集LaSOT&#xff0c;包含超过352万帧手工标注的图片和1400个视频&#xff0c;这也是目前为止最大的拥有密集标注的单目标跟踪数据集。论文《LaSOT: A High-qua…

centos7中nfs文件系统的使用

需求&#xff1a;file01:1.1.1.1(内网ip 172.20.103.212)&#xff0c;file02:2.2.2.2(内网ip 172.20.103.211) 这两台机器的 /dev/mapper/myvg-mylv /data 这个盘都挂载到 video01 47.254.78.171, video02 47.254.83.81 这两台机器上即将file01和file02的/data目录都挂载到vid…

在图像变换中用最小二乘法求解仿射变换参数

设原图像为f(x,y)&#xff0c;畸变后的图像为F(X,Y)&#xff0c;要将F(X,Y)恢复为f(x,y)&#xff0c;就是要找到(X,Y)坐标与(x,y)坐标的转换关系&#xff0c;这个转换关系称为坐标变换&#xff0c;表示为(x,y)T(X,Y)。 景物在成像过程中产生的扭曲&#xff0c;会使图像的比例失…

showModalDialog关闭子窗口,并刷新父窗口

一、用法&#xff1a;window.showModalDialog(url,args,dialogWidth650px;scrollno;dialogHeight250px;statusno; ); 二、关闭子窗口&#xff0c;并刷新父窗口 想在showModalDialog打开的窗口中提交表单且不打开新窗口 只需在打开的页面的<head>中加入<base target&qu…

cvDrawContours:在图像上绘制外部和内部轮廓

转自&#xff1a;http://www.aiseminar.cn/html/18/t-618.html?action-uchimage 函数cvDrawContours用于在图像上绘制外部和内部轮廓。当thickness > 0 时&#xff0c;绘制轮廓线&#xff1b;否则填充由轮廓包围的部分。 void cvDrawContours( CvArr *img, CvSeq* contour,…

Python最抢手、Go最有前途,7000位程序员揭秘2019软件开发现状

作者 | 屠敏 整理报告来源 | JetBrains转载自 CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;互联网的下半场&#xff0c;科技公司为面对更加严峻的竞争环境&#xff0c;越来越重视开源节流。而对于身处其中且撑起 IT 半边天的技术人&#xff0c;如今如何了&#xff1f;从…

main函数参数

参考&#xff1a;Where Does GCC Look to Find its Header Files? 命令行参数 VS 程序参数 ./a.out 1 2 3 4 5 6 1 2 3 4 5 6是程序参数&#xff0c;是传给a.out这个程序处理的&#xff0c;main里面的argv来接收 ./a.out 1 2 3 4 5 6完整的这一串才是命令行参数 代码演示 如下…

转载 load-on-startup的用法

转载于:http://www.ituring.com.cn/article/50477 Web.xml中的Servlet中的配置&#xff1a; <servlet><servlet-name>createBlog</servlet-name><servlet-class>com.cnblogs.CreateBlog</servlet-class><load-on-startup>0</load-on-s…

商汤62篇论文入选CVPR 2019,一览五大方向最新研究进展

&#xff08;图源自视觉中国&#xff09;作为与ICCV、ECCV并称为计算机视觉领域三大国际会议之一&#xff0c;本届CVPR大会共收到5265篇有效投稿&#xff0c;接收论文1300篇&#xff0c;接收率为25.2%。商汤科技CVPR 2019录取论文在多个领域实现突破作为国内CV领域的明星公司&a…

cvSaveImage保存图像

转自&#xff1a;http://blog.csdn.net/luhuillll/archive/2009/10/28/4739471.aspx opencv保存图象直接使用cvSaveImage,这个函数.但是windows位图的图象格式是RGBt格式,而opencv的图象存储格式是BGR. 这样导致保存的图象失真.在windows下查看图象好象变绿色了.所以在保存图象…

软工实践原型设计——PaperRepositories

软工实践原型设计——PaperRepositories 写在前面 本次作业链接队友&#xff08;031602237吴杰婷&#xff09;博客链接pdf文件地址原型设计地址(加载有点慢...)结对成员:031602237吴杰婷 & 031602636许舒玲原型设计工具:Axure RP 8PSP表格 PSP3.1Personal Software Process…