Python實(shí)現(xiàn)藍(lán)線挑戰(zhàn)特效的示例代碼
在抖音曾經(jīng)火了一陣子的藍(lán)線挑戰(zhàn)特效,其原理很簡單:在藍(lán)線經(jīng)過后保留本幀的部分像素,形成蒙板圖片,未經(jīng)過處照常切換幀圖片,再將蒙版圖片貼到每幀圖片上。本著我上我也行的想法,試著用opencv-python實(shí)現(xiàn)這個(gè)效果,做了攝像頭版本和視頻處理版本。
圖源:抖音
圖源: PPT
1. 攝像頭版本
從上述描述可知,在攝像頭版本中可規(guī)定每幀取固定寬度像素,如2個(gè)像素,假設(shè)視頻尺寸為640*480,則需要480/2=240幀,若視頻幀率(每秒的幀數(shù))為30,則運(yùn)行8秒,實(shí)際受計(jì)算速度等影響會(huì)略大于這個(gè)值,以下為關(guān)鍵部位代碼:
(1)從攝像頭獲取每幀圖像
video = CV2.VideoCapture(0, CV2.CAP_DSHOW) ret, frame = video.read() # frame為np數(shù)組,寬100高200時(shí),數(shù)組形狀為200 * 100 *3 frame = CV2.flip(frame,1) # 左右翻轉(zhuǎn)圖像為鏡像
(2)制作蒙版圖片,并取每幀的固定數(shù)量的像素
#通過row_index記錄當(dāng)前的行索引,獲取像素作為蒙版圖片 canvas[row_index:row_index + pixel_number_each_frame] = frame[row_index:row_index + pixel_number_each_frame] row_index += pixel_number_each_frame # 每次運(yùn)行增加固定像素寬度 if row_index + width_blueline < hight: # 避免因?yàn)樵黾庸潭ㄏ袼?,?dǎo)致超出圖像的高度 frame[:row_index] = canvas[:row_index] # 將每幀的圖像上部替換為蒙版圖片 frame[row_index:row_index+ width_blueline] = array_blueline # 添加藍(lán)線矩陣 # 窗口顯示,BUG在于frame數(shù)據(jù)為浮點(diǎn)數(shù)時(shí)默認(rèn)RGB數(shù)值范圍0~1,當(dāng)為整數(shù)時(shí)為0~255 CV2.imshow('Viewer', frame / 255)
(3)將處理完的圖片及時(shí)保存,便于后期導(dǎo)出視頻
CV2.imwrite(f'{output_frame_dirpath}/{count}.jpg', frame)
(4)合成視頻
def img_to_video(output_video_path, frame_dirpath, fps): """ 將處理好的幀圖片合成視頻 :param output_video_path: 輸出視頻的地址 :param frame_dirpath: 幀圖片所在文件夾地址 :param fps: 輸出幀率 :return: None """ img = CV2.imread(f"{frame_dirpath}/1.jpg") hight, width, _ = img.shape fourcc = CV2.VideoWriter_fourcc(*'mp4v') videoWriter = CV2.VideoWriter(output_video_path, fourcc, fps, (width, hight)) order = [int(i.strip(".jpg")) for i in os.listdir(frame_dirpath) if i.endswith(".jpg")] jpglist = [f"{frame_dirpath}/{i}.jpg" for i in sorted(order)] for i, jpg in enumerate(jpglist): img = CV2.imread(filename=jpg) videoWriter.write(img) print(f"將字符畫寫入視頻, 進(jìn)度{(i + 1)}/{len(jpglist)}!") videoWriter.release() print(f"{output_video_path} 輸出完成!")
2. 視頻處理版本
與攝像頭版本不同,視頻版本需要獲取視頻信息以做處理。
(1)將視頻抽幀為圖片
def video_to_img(frame_dirpath, video_path): """ 將視頻抽取為幀圖片以便處理 :param frame_dirpath: 存放抽取好的幀圖片文件夾地址 :param video_path: 視頻地址 :return: None """ vc = CV2.VideoCapture(video_path) c = 0 ret = vc.isOpened() while ret: c += 1 ret, frame = vc.read() if ret: CV2.imwrite(f'{frame_dirpath}/{c}.jpg', frame) print(f'生成{frame_dirpath}/{c}.jpg') else: break vc.release() print("視頻按各幀提取完成!")
(2)獲取視頻基本信息
def get_video_msg(video_path): """ 獲取視頻的基本信息 :param video_path: 視頻地址 :return: [幀數(shù)量,[寬度,高度],幀率] """ cap = CV2.VideoCapture(video_path) if cap.isOpened(): frame_number = cap.get(7) width = cap.get(3) hight = cap.get(4) fps = cap.get(5) return [frame_number, [width, hight], fps] return [-1, -1, -1, [-1, -1], -1]
(3)計(jì)算相關(guān)參數(shù)。新視頻的時(shí)長即為掃描時(shí)長,即每幀抽取像素= 圖片高度 / 總幀數(shù),此時(shí)需要取整,且取整誤差=圖片高度 - 每幀抽取像素* 總幀數(shù),不處理會(huì)導(dǎo)致藍(lán)線無法在時(shí)長內(nèi)掃描完整個(gè)高度。
array_blueline = np.array([[[255, 255, 0] for _ in range(width)] for _ in range(width_blueline)]) pixel_number_each_frame = int(hight / frame_number) # 每次取幀截取的像素范圍 err = hight - pixel_number_each_frame * frame_number - 3 # 誤差值分散到每幀,留3個(gè)像素給藍(lán)線
(4)將誤差分散到較前的幀圖片中
if err_count < err: canvas[row_index:row_index + pixel_number_each_frame + 1] = img[row_index:row_index + pixel_number_each_frame + 1] row_index += pixel_number_each_frame + 1 err_count += 1 # 計(jì)算誤差部分是否使用完 else: canvas[row_index:row_index + pixel_number_each_frame] = img[row_index:row_index + pixel_number_each_frame] row_index += pixel_number_each_frame if row_index + width_blueline <= hight: # 避免索引跑出圖片范圍而報(bào)錯(cuò) img[:row_index] = canvas[:row_index] img[row_index:row_index+ width_blueline] = array_blueline
(5)將圖片重新合成視頻,同攝像頭版本,不再贅述
到此這篇關(guān)于Python實(shí)現(xiàn)藍(lán)線挑戰(zhàn)特效的示例代碼的文章就介紹到這了,更多相關(guān)Python藍(lán)線挑戰(zhàn)特效內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python3創(chuàng)建Django項(xiàng)目的幾種方法(3種)
這篇文章主要介紹了Python3創(chuàng)建Django項(xiàng)目的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06對django后臺admin下拉框進(jìn)行過濾的實(shí)例
今天小編就為大家分享一篇對django后臺admin下拉框進(jìn)行過濾的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07基于Python3制作一個(gè)帶GUI界面的小說爬蟲工具
這篇文章主要為大家介紹了一個(gè)通過Python3制作的帶GUI界面的小說爬蟲工具,用來從筆趣閣爬取小說。感興趣的小伙伴可以跟隨小編一起動(dòng)手嘗試一下2022-02-02Python中Cryptography庫實(shí)現(xiàn)加密解密
Python中Cryptography庫給你的文件加把安全鎖,本文主要介紹了Python中Cryptography庫實(shí)現(xiàn)加密解密,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02Python+tkinter實(shí)現(xiàn)音樂下載軟件的制作
平常我們下載的歌曲,都是各種妖魔鬼怪的格式橫行,想下載下來用一下都不行,還只能在它的播放器內(nèi)聽,這誰受得了~本文就來用Python制作個(gè)音樂下載軟件,需要的可以參考一下2022-09-09