1. 程式人生 > 其它 >OpenCV開發實戰1——抖音哈哈鏡效果

OpenCV開發實戰1——抖音哈哈鏡效果

前言

在抖音中,我們經常看到各種抖音玩家都喜歡使用哈哈鏡效果。那麼什麼是哈哈鏡呢?

在現實生活中,哈哈鏡是指一種表面凹凸不平的鏡子,可以反應出人像及物體的扭曲面貌。簡單點來說就是拉伸人臉(物件),或者壓縮人臉(物體)的效果。

哈哈鏡實現原理

假設輸入影象的寬高為wh,影象中心點的座標為(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

同理,壓縮縮小的公式如下(compress為壓縮強度):

x=cos(atan2(ty,tx))compresssqrt(sqrt(txtx+tyty))+cx
x=cos(atan2(ty,tx))compresssqrt(sqrt(txtx+tyty))+cy

原始影象:

基於OpenCV的哈哈鏡放大實現

既然我們瞭解了其數學公式以及其實現的原理,下面我們來直接實現哈哈鏡的放大效果。具體程式碼如下所示:

import cv2
import math
#哈哈鏡放大效果實現
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<w和y<h來判斷防止越界。

基於OpenCV的哈哈鏡縮小實現

具體程式碼如下所示:

import cv2
import math

#哈哈鏡縮小效果實現
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("lena.jpg")
    frame = reduce_effect(img)
    cv2.imshow("lena1", img)
    cv2.imshow("lena2", frame)
    cv2.waitKey()
    cv2.destroyAllWindows()

執行後的效果如下:

視訊實現哈哈鏡效果

抖音上面的哈哈鏡都是動態的,並不是單一的圖片這麼變來變去。其實,只要我們集合攝像頭視訊錄製功能,就可以完成視訊哈哈鏡的動態效果。具體程式碼如下:

import cv2
import math

#哈哈鏡放大效果實現
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

#哈哈鏡縮小效果實現
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__":
    cap = cv2.VideoCapture("video.mp4")
    while (cap.isOpened()):
        ret, frame = cap.read()
        enlarge_img = enlarge_effect(frame)
        frame = reduce_effect(frame)
        cv2.imshow('video1', enlarge_img)
        cv2.imshow('video2', frame)
        c = cv2.waitKey(1)
        if c == 27:
            break
    cap.release()
    cv2.destroyAllWindows()