Article directory
overview
overview:
The puzzle effect is an artistic effect that cuts an image into adjacent squares and rearranges them. Different modes can be considered when generating a puzzle effect, including whether to consider intervals and how to handle non-divisible parts.
Ignore intervals and ignore parts that are not divisible:
There is no space between adjacent squares, and parts whose heights are not divisible are ignored.
The example image shows the squares arranged closely without any gaps, and the non-divisible parts are discarded.
Irrespective of the spacing, the parts that are not divisible are filled with white space:
There is no gap between adjacent squares, and the parts whose height is not divisible are filled with white.
The example image shows seamless connections between squares, and the parts whose heights are not divisible are filled with white.
Consider the gap and ignore the parts that are not divisible:
There is a gap between adjacent squares, the distance is 3 pixels, and the parts whose height is not divisible are ignored directly.
The example diagram shows the intervals between squares, and the parts that are not divisible are discarded.
Consider the spacing and fill the parts that are not divisible with white space:
There is a gap between adjacent squares with a spacing of 3 pixels, and fill the parts whose height is not divisible with white.
The example image demonstrates the spacing between squares, and the parts whose height is not divisible are filled with white.
common arrangement
In order to unify the above code, we set the general configuration items as follows:
config = {
"cell_num":7,
"whether_crop_image_height": True,
"whether_with_gap": True,
"gap_width":3
}
In the above configuration, the meanings of each item are as follows:
cell_num: represents the number of cells divided into each row
whether_crop_image_height: Indicates whether to fill in blanks for parts of the height that are not divisible
whether_with_gap: indicates whether there is a gap between adjacent squares
gap_width: represents the size of the gap between adjacent squares
Regardless of interval code implementation
1). Get the number of grids in each row and the input image information
w_count = config['cell_num']
src_height = img.shape[0]
src_width = img.shape[1]
2). Calculate the length of each grid and the width of the resulting image
sub_length = int(src_width / w_count)
new_width = sub_length * w_count
3). Calculate the height of the resulting image based on whether the height needs to be filled in the blanks.
if config['whether_crop_image_height']:
h_count = int(src_height / sub_length)
else:
h_count = math.ceil(src_height / sub_length)
new_height = sub_length * h_count
4).Assign values to the result graph
img_t = np.zeros(shape=(new_height,new_width,3),dtype=np.uint8) + 255
if config['whether_crop_image_height']:
img_t = img[:new_height,:new_width,:]
else:
img_t[:src_height, :new_width, :] = img[:src_height, :new_width, :]
5).Picture grid
for x_i in range(1, w_count):
cv2.line(img_t,(x_i*sub_length,0),(x_i*sub_length,new_height-1),color=(205,205,74),thickness=1)
for y_i in range(1, h_count):
cv2.line(img_t,(0,y_i*sub_length),(new_width-1,y_i*sub_length), color=(205,205,74), thickness=1)
Complete code:
import cv2
import numpy as np
import math
# 通用配置
config = {
"cell_num": 7,
"whether_crop_image_height": True,
"whether_with_gap": False,
"gap_width": 0
}
# 读取图像
img = cv2.imread("img.png")
# 获取每行格子数目和输入图像信息
w_count = config['cell_num']
src_height = img.shape[0]
src_width = img.shape[1]
# 计算每个格子的长度以及结果图像的宽度
sub_length = int(src_width / w_count)
new_width = sub_length * w_count
# 根据是否需要对高度进行空白填充,计算结果图像的高度
if config['whether_crop_image_height']:
h_count = int(src_height / sub_length)
else:
h_count = math.ceil(src_height / sub_length)
new_height = sub_length * h_count
# 对结果图进行赋值
img_t = np.zeros(shape=(new_height, new_width, 3), dtype=np.uint8) + 255
if config['whether_crop_image_height']:
img_t = img[:new_height, :new_width, :]
else:
img_t[:src_height, :new_width, :] = img[:src_height, :new_width, :]
# 画格子
for x_i in range(1, w_count):
cv2.line(img_t, (x_i * sub_length, 0), (x_i * sub_length, new_height-1), color=(205, 205, 74), thickness=1)
for y_i in range(1, h_count):
cv2.line(img_t, (0, y_i * sub_length), (new_width-1, y_i * sub_length), color=(205, 205, 74), thickness=1)
# 展示生成的拼图效果
cv2.imshow('Mosaic Effect', img_t)
cv2.waitKey(0)
cv2.destroyAllWindows()
Results with padding:
import cv2
import numpy as np
import math
# 通用配置
config = {
"cell_num": 7,
"whether_crop_image_height": True,
"whether_with_gap": False,
"gap_width": 0
}
# 读取图像
img = cv2.imread("img.png")
# 获取每行格子数目和输入图像信息
w_count = config['cell_num']
src_height = img.shape[0]
src_width = img.shape[1]
# 计算每个格子的长度、间隔长度以及结果图像的宽度
sub_length = int(src_width / w_count)
gap_length = int(config["gap_width"])
new_width = sub_length * w_count + gap_length * (w_count - 1)
# 根据是否需要对高度进行空白填充,计算结果图像的高度
if config['whether_crop_image_height']:
h_count = int((src_height + gap_length) / (sub_length + gap_length))
else:
h_count = math.ceil((src_height + gap_length) / (sub_length + gap_length))
new_height = sub_length * h_count + gap_length * (h_count - 1)
# 对结果图进行赋值
img_t = np.zeros(shape=(new_height, new_width, 3), dtype=np.uint8) + 255
if config['whether_crop_image_height']:
for i in range(h_count):
for j in range(w_count):
begin_x = sub_length * j
begin_y = sub_length * i
src_x = gap_length * j + begin_x
src_y = gap_length * i + begin_y
img_t[src_y:src_y + sub_length, src_x:src_x + sub_length, :] = img[begin_y:begin_y + sub_length, begin_x:begin_x + sub_length, :]
else:
for i in range(h_count):
for j in range(w_count):
begin_x = sub_length * j
begin_y = sub_length * i
src_x = gap_length * j + begin_x
src_y = gap_length * i + begin_y
if i < h_count - 1:
img_t[src_y:src_y + sub_length, src_x:src_x + sub_length, :] = img[begin_y:begin_y + sub_length, begin_x:begin_x + sub_length, :]
else:
diff_height = src_height - sub_length * (h_count - 1)
img_t[src_y:src_y + diff_height, src_x:src_x + sub_length, :] = img[begin_y:begin_y + diff_height, begin_x:begin_x + sub_length, :]
# 展示生成的拼图效果
cv2.imshow('Mosaic Effect with Fill', img_t)
cv2.waitKey(0)
cv2.destroyAllWindows()
不考虑间隔,带填充的情况:
img_t = np.zeros(shape=(new_height, new_width, 3), dtype=np.uint8) + 255
if config['whether_crop_image_height']:
img_t = img[:new_height, :new_width, :]
else:
img_t[:src_height, :new_width, :] = img[:src_height, :new_width, :]
考虑间隔,带填充的情况:
img_t = np.zeros(shape=(new_height, new_width, 3), dtype=np.uint8) + 255
if config['whether_crop_image_height']:
for i in range(h_count):
for j in range(w_count):
begin_x = sub_length * j
begin_y = sub_length * i
src_x = gap_length * j + begin_x
src_y = gap_length * i + begin_y
img_t[src_y:src_y + sub_length, src_x:src_x + sub_length, :] = img[begin_y:begin_y + sub_length, begin_x:begin_x + sub_length, :]
else:
for i in range(h_count):
for j in range(w_count):
begin_x = sub_length * j
begin_y = sub_length * i
src_x = gap_length * j + begin_x
src_y = gap_length * i + begin_y
if i < h_count - 1:
img_t[src_y:src_y + sub_length, src_x:src_x + sub_length, :] = img[begin_y:begin_y + sub_length, begin_x:begin_x + sub_length, :]
else:
diff_height = src_height - sub_length * (h_count - 1)
img_t[src_y:src_y + diff_height, src_x:src_x + sub_length, :] = img[begin_y:begin_y + diff_height, begin_x:begin_x + sub_length, :]
In the case of padding, the portion of the height that is not divisible is padded with blanks. Puzzles with padding will look neater, while without padding there may be some truncation.
Consider interval code implementation
1). Get the number of grids in each row and the input image information
w_count = config['cell_num']
src_height = img.shape[0]
src_width = img.shape[1]
2). Calculate the length of each grid, the length of the interval and the width of the resulting image
sub_length = int(src_width / w_count)
gap_length = int(config["gap_width"])
new_width = sub_length * w_count + gap_length * (w_count -1)
3). Calculate the height of the resulting image based on whether the height needs to be filled in the blanks.
if config['whether_crop_image_height']:
h_count = int( (src_height + gap_length) / (sub_length+gap_length))
else:
h_count = math.ceil((src_height + gap_length) / (sub_length+gap_length))
new_height = sub_length * h_count + gap_length * (h_count-1)
4).Assign values to the result graph
img_t = np.zeros(shape=(new_height,new_width,3),dtype=np.uint8) + 255
if config['whether_crop_image_height']:
for i in range(h_count):
for j in range(w_count):
begin_x = sub_length * j
begin_y = sub_length * i
src_x = gap_length * j + begin_x
src_y = gap_length * i + begin_y
img_t[src_y:src_y+sub_length,src_x:src_x + sub_length,:] = img[begin_y:begin_y + sub_length,begin_x:begin_x + sub_length, :]
else:
for i in range(h_count):
for j in range(w_count):
begin_x = sub_length * j
begin_y = sub_length * i
src_x = gap_length * j + begin_x
src_y = gap_length * i + begin_y
if i<h_count-1:
img_t[src_y:src_y+sub_length,src_x:src_x + sub_length,:] = img[begin_y:begin_y + sub_length,begin_x:begin_x + sub_length, :]
else:
diff_height = src_height - sub_length * (h_count-1)
img_t[src_y:src_y + diff_height, src_x:src_x + sub_length, :] = img[begin_y:begin_y + diff_height,begin_x:begin_x + sub_length, :]
All code
import cv2
import numpy as np
import math
# 通用配置
config = {
"cell_num": 7,
"whether_crop_image_height": True,
"whether_with_gap": True,
"gap_width": 3
}
# 读取图像
img = cv2.imread("img.png")
# 获取每行格子数目和输入图像信息
w_count = config['cell_num']
src_height = img.shape[0]
src_width = img.shape[1]
# 计算每个格子的长度、间隔长度以及结果图像的宽度
sub_length = int(src_width / w_count)
gap_length = int(config["gap_width"])
new_width = sub_length * w_count + gap_length * (w_count - 1)
# 根据是否需要对高度进行空白填充,计算结果图像的高度
if config['whether_crop_image_height']:
h_count = int((src_height + gap_length) / (sub_length + gap_length))
else:
h_count = math.ceil((src_height + gap_length) / (sub_length + gap_length))
new_height = sub_length * h_count + gap_length * (h_count - 1)
# 对结果图进行赋值
img_t = np.zeros(shape=(new_height, new_width, 3), dtype=np.uint8) + 255
if config['whether_crop_image_height']:
for i in range(h_count):
for j in range(w_count):
begin_x = sub_length * j
begin_y = sub_length * i
src_x = gap_length * j + begin_x
src_y = gap_length * i + begin_y
img_t[src_y:src_y + sub_length, src_x:src_x + sub_length, :] = img[begin_y:begin_y + sub_length, begin_x:begin_x + sub_length, :]
else:
for i in range(h_count):
for j in range(w_count):
begin_x = sub_length * j
begin_y = sub_length * i
src_x = gap_length * j + begin_x
src_y = gap_length * i + begin_y
if i < h_count - 1:
img_t[src_y:src_y + sub_length, src_x:src_x + sub_length, :] = img[begin_y:begin_y + sub_length, begin_x:begin_x + sub_length, :]
else:
diff_height = src_height - sub_length * (h_count - 1)
img_t[src_y:src_y + diff_height, src_x:src_x + sub_length, :] = img[begin_y:begin_y + diff_height, begin_x:begin_x + sub_length, :]
# 绘制间隔
if config['whether_with_gap']:
for i in range(h_count):
for j in range(w_count - 1):
begin_x = sub_length * (j + 1) + gap_length * j
begin_y = sub_length * i + gap_length * i
cv2.line(img_t, (begin_x, begin_y), (begin_x, begin_y + sub_length), color=(205, 205, 74), thickness=1)
# 展示生成的带填充和间隔的拼图效果
cv2.imshow('Mosaic Effect with Fill and Gap', img_t)
cv2.waitKey(0)
cv2.destroyAllWindows()
summary
By using the OpenCV library and the Python programming language, the image puzzle effect is generated.
Puzzle effect generation: According to user needs, two different puzzle effect generation methods are implemented.
One is to ignore the spacing, and you can choose whether to fill in the blanks for parts whose height is not divisible; the other is to consider the spacing, and you can choose whether there is a gap between adjacent squares, and the distance between them. Size, you can also choose whether to fill in the blanks for parts whose height is not divisible.
General configuration: General configuration items are introduced. Users can modify the configuration to adjust the number of grids of the puzzle, whether to crop the height, whether to consider the interval and the width of the interval and other parameters.
Code optimization: Encapsulates some functional functions to make the code more modular and readable.