还在想这次活动做什么的时候, 偶尔发现了手机里很早之前给npy拍的照片, 那叫一个丑啊…删又不舍得, 想了想打算给它做一点处理, 也就想到了蒙太奇风格
这里我们需要目标图像target.jpg
, "精挑细选"一张npy的照片, 另外很多素材图像, 理论上可以是任意的图像. 但是为了更有意义, 可以选择旅游照啊, 自拍啊啥的和npy有关的. 我这里为了方便就选择了lfw
人脸数据集, 下载链接在这
准备好这些图像那准备工作就完成了
接着需要对target.jpg
和素材图象做一些预处理, 要做的事情如下:
target.jpg
的大小是1080x1440
, 那么选取10000张(估算时需要预留一部分以免素材匹配不上不够用)来拼成target.jpg
的话, 每张素材的大小大概是10.8x14.4
, 也就是10x15
target.jpg
调整大小到一个合理的值, 使得长宽刚好能被调整后的素材大小整除, 比如针对上面的10x15
的大小, 应该将1081x1445
的target.jpg
调整到1080x1440
opencv
有resize
函数可以方便地调整图像大小, 借助os
库, 可以对一个目录下的所有文件进行该操作:
def gen_all_images_src(self):
"""
将数据集中的所有jpg图像resize到25x25并存入DIR_IMAGES_SRC
"""
self.log_string('>> gen_all_images_src ...')
cnt = 0
for dir_cur in os.listdir(self.__DIR_DATASET):
self.log_string('>> extracting from {}'.format(os.path.join(self.__DIR_DATASET, dir_cur)))
for file in os.listdir(os.path.join(self.__DIR_DATASET, dir_cur)):
self.log_string('>> detected files: ' + str(os.listdir(os.path.join(self.__DIR_DATASET, dir_cur))))
img = cv.imread(os.path.join(self.__DIR_DATASET, dir_cur) + '/' + file)
save_name = self.__DIR_IMAGES_SRC + 'image-{}.jpg'.format(cnt)
img_resized = cv.resize(img, (20, 20))
self.log_string('>> writing to {}'.format(save_name))
cv.imwrite(save_name, img_resized)
cnt += 1
self.log_string('>> gen_all_images_src done! \n\n\n')
做完这两步那预处理也完成了
同样, 直接调用opencv
的calcHist
函数就好, 为方便后续使用, 将所有素材的直方图结果存入一个dict
字典, key
为素材的路径, value
为素材的直方图
def gen_hist_dict(self):
"""
统计所有images_src的直方图并保存
:return:
"""
self.log_string('>> calculating hist ...')
hist_dict = {
}
for file in os.listdir(self.__DIR_IMAGES_SRC):
img = cv.imread(os.path.join(self.__DIR_IMAGES_SRC, file))
hist = []
for i in range(3):
ht = cv.calcHist([img], [i], None, [256], [0, 256])
hist.append(ht)
hist_dict[file] = hist
self.log_string('>> calculating hist done ! \n\n\n')
self.__hist_dict = hist_dict
将target.jpg
划分成若干个区域, 对每个区域做暴力匹配. 比如target.jpg
大小为1080x1440
, 素材大小是10x15
, 那么也就是将target.jpg
划分成108x96
个区域, 对这些区域做暴力匹配:
def match_replace(self):
"""
将素材拼成目标图像
"""
self.log_string(">> matching and replacing ...")
height, width, channel = self.__TARGET_SHAPE
image_target = deepcopy(self.__image_target)
dy, dx = self.__RESIEZE_SHAPE
for i in range(0, height, dy):
for j in range(0, width, dx):
img = image_target[i:i + dy, j:j + dx, 0:3]
hist = []
for k in range(3):
ht = cv.calcHist([img], [k], None, [256], [0, 256])
hist.append(ht)
rename = 0
sim = 0.0
for key in self.__hist_dict:
match0 = cv.compareHist(hist[0], self.__hist_dict[key][0], cv.HISTCMP_CORREL)
match1 = cv.compareHist(hist[1], self.__hist_dict[key][1], cv.HISTCMP_CORREL)
match2 = cv.compareHist(hist[2], self.__hist_dict[key][2], cv.HISTCMP_CORREL)
match = match0 + match1 + match2
if match >= sim:
sim = match
rename = key
if i + dy <= height and j + dx <= width:
image_target[i:i + dy, j:j + dx, 0:3] = cv.imread(os.path.join(self.__DIR_IMAGES_SRC, rename))
cv.imwrite(os.path.join(self.__DIR_IMAGES, 'generate.jpg'), image_target)
self.log_string('>> matching and replacing done ! \n\n\n ')
其中需要注意的是, 同一幅图像,操作系统中显示的大小是1080x1440
, 但是在opencv
里面的shape
是1440x1080
, 两个轴是反的.
得到generate.jpg
就算大功告成了, 至此我们已经完成了图像风格的蒙太奇转换, 但是效果还不是很理想, 如下:
因此我们将target.jpg
与generate.jpg
做一个加权平均:
def mixup(self):
"""
将生成的图像与目标图像做mixup,得到更好的效果
"""
self.log_string('mixing ...')
image1 = self.__image_target
image2 = cv.imread(os.path.join(self.__DIR_IMAGES, 'generate.jpg'))
dst = cv.addWeighted(image1, 0.2, image2, 0.8, 3)
cv.imwrite(os.path.join(self.__DIR_IMAGES, 'mixed.jpg'), dst)
self.log_string('mixing done ! \n\n\n')
得到的效果明显好很多:
等审核通过后点击下载链接即可下载
加上argparse
后封装好的hithub链接在这:
git clone https://github.com/poorCodingMan/MontageTransform.git
该来的总会来的…
Every once in a while you find someone who’s iridescent, and when you do, nothing will ever compare. --