предисловие
В Douyin мы часто видим, что различные исполнители Douyin любят использовать эффект фанка. Так что же такое фанковое зеркало?
В реальной жизни зеркало в стиле фанк относится к зеркалу с неровной поверхностью, отражающей искаженный вид портретов и предметов. Проще говоря, это эффект растяжения лица (объекта) или сжатия лица (объекта).
Принцип реализации веселого зеркала следующий:
Предположим, что ширина и высота входного изображения равны w и h, а координаты центральной точки изображения равны (cx, cy). Тогда расстояние от любой точки (x, y) изображения до центральной точки равно (x-cx), (y-cy).
Затем потяните вверх и увеличьте масштаб, радиус преобразования изображения равен r (r — размер размаха прикольного зеркала), а формула выглядит следующим образом:
x=(tx/2)(sqrt(txtx+tyty)/r)+cx y=(ty/2)(sqrt(txtx+tyty)/r)+cy
Точно так же формула для сжатия и сжатия выглядит следующим образом (сжатие - это сила сжатия): х=cos(atan2(ty,tx))compresssqrt(sqrt(txtx+tyty))+cx y=cos(atan2(ty,tx))compresssqrt(sqrt(txtx+tyty))+cy
Зеркальный эффект увеличения
Теперь, когда мы понимаем его математическую формулу и принцип его реализации, давайте непосредственно реализуем эффект увеличения фанкового зеркала. Конкретный код выглядит следующим образом:
#哈哈镜放大效果实现
def enlarge_effect(img):
h, w, n = img.shape
cx = w / 2
cy = h / 2
radius = 100#该值可以自行定义,它决定了哈哈镜的大小,当图像很大时,应该相应的调大
r = int(radius / 2.0)
new_img = img.copy()
for i in range(w):
for j in range(h):
tx = i - cx
ty = j - cy
distance = tx * tx + ty * ty
if distance < radius * radius:
x = int(int(tx / 2.0) * (math.sqrt(distance) / r) + cx)
y = int(int(ty / 2.0) * (math.sqrt(distance) / r) + cy)
if x < w and y < h:
new_img[j, i, 0] = img[y, x, 0]
new_img[j, i, 1] = img[y, x, 1]
new_img[j, i, 2] = img[y, x, 2]
return new_img
if __name__ == "__main__":
img = cv2.imread("4.jpg")
enlarge_img = enlarge_effect(img)
cv2.imshow("4", enlarge_img)
cv2.waitKey()
cv2.destroyAllWindows()
После запуска эффект следующий:
Следует отметить, что приведенный выше процесс вычисления может привести к появлению чисел с плавающей запятой, а значение пикселя должно быть целым числом. Следовательно, чтобы обеспечить достоверность значения пикселя, приведение int() должно быть выполнено после завершения процесса вычисления. Кроме того, при вычислении значений x и y это может привести к превышению диапазона координат изображения, поэтому для оценки необходимо использовать x
Эффект уменьшения зеркала
Ниже мы непосредственно реализуем эффект уменьшения фанкового зеркала. Конкретный код выглядит следующим образом:
def reduce_effect(img):
h, w, n = img.shape
cx = w / 2
cy = h / 2
radius = 100
r = int(radius / 2.0)
compress = 8
new_img = img.copy()
for i in range(w):
for j in range(h):
tx = i - cx
ty = j - cy
x = int(cx + (math.sqrt(math.sqrt(tx * tx + ty * ty)) * compress * math.cos(math.atan2(ty, tx))))
y = int(cy + (math.sqrt(math.sqrt(tx * tx + ty * ty)) * compress * math.sin(math.atan2(ty, tx))))
if x < 0 and x > w:
x = 0
if y < 0 and y > h:
y = 0
if x < w and y < h:
new_img[j, i, 0] = img[y, x, 0]
new_img[j, i, 1] = img[y, x, 1]
new_img[j, i, 2] = img[y, x, 2]
return new_img
if __name__ == "__main__":
img = cv2.imread("4.jpg")
enlarge_img = enlarge_effect(img)
frame = reduce_effect(img)
cv2.imshow("1", img)
cv2.imshow("2", enlarge_img)
cv2.imshow("3", frame)
cv2.waitKey()
cv2.destroyAllWindows()
После запуска эффект следующий:
Прямое видео для достижения эффектного зеркального эффекта
Все веселые зеркала на Douyin динамичны, а не просто одна картинка. На самом деле, пока мы интегрируем функцию записи видео на фронтальную камеру, мы можем дополнить динамический эффект забавного видеозеркала. Конкретный код выглядит следующим образом:
if __name__ == "__main__":
cap = cv2.VideoCapture(0)
while (cap.isOpened()):
ret, frame = cap.read()
frame=enlarge_effect(frame)
cv2.imshow('video', frame)
c = cv2.waitKey(1)
if c == 27:
break
cap.release()
cv2.destroyAllWindows()