OpenCV (47) --- Реализовать эффект фанк-зеркала Douyin

искусственный интеллект OpenCV
OpenCV (47) --- Реализовать эффект фанк-зеркала Douyin

предисловие

В 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()