最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于opencv對(duì)高空拍攝視頻消抖處理方法

 更新時(shí)間:2022年10月24日 10:07:05   作者:js君  
這篇文章主要介紹了基于opencv對(duì)高空拍攝視頻消抖處理,首先對(duì)視頻進(jìn)行抽第一幀與最后一幀,為什么抽取兩幀?這樣做的主要目的是,我們?cè)谧鰩瑢?duì)齊時(shí),使用幀中靜態(tài)物的關(guān)鍵點(diǎn)做對(duì)齊,需要的朋友可以參考下

一、問(wèn)題背景

無(wú)人機(jī)在拍攝視頻時(shí),由于風(fēng)向等影響因素,不可避免會(huì)出現(xiàn)位移和旋轉(zhuǎn),導(dǎo)致拍攝出的畫(huà)面存在平移和旋轉(zhuǎn)的幀間變換, 即“抖動(dòng)” 抖動(dòng)會(huì)改變目標(biāo)物體 (車(chē)輛、行人) 的坐標(biāo),給后續(xù)的檢測(cè)、跟蹤任務(wù)引入額外誤差,造成數(shù)據(jù)集不可用。

原效果

目標(biāo)效果

理想的無(wú)抖動(dòng)視頻中,對(duì)應(yīng)于真實(shí)世界同一位置的背景點(diǎn)在不同幀中的坐標(biāo)應(yīng)保持一致,從而使車(chē)輛、行人等目標(biāo)物體的坐標(biāo)變化只由物體本身的運(yùn)動(dòng)導(dǎo)致,而不包含相機(jī)的運(yùn)動(dòng) 抖動(dòng)可以由不同幀中對(duì)應(yīng)背景點(diǎn)的坐標(biāo)變換來(lái)描述

二、量化指標(biāo)

抖動(dòng)可以用相鄰幀之間的 x 方向平移像素 dx,y 方向平移像素 dy,旋轉(zhuǎn)角度 da,縮放比例 s 來(lái)描述,分別繪制出 4 個(gè)折線圖,根據(jù)折線圖的走勢(shì)可以判斷抖動(dòng)的程度 理想的無(wú)抖動(dòng)視頻中,dx、dy、da 幾乎始終為 0,s 幾乎始終為 1。

三、技術(shù)思路

我們最終實(shí)現(xiàn),將視頻的所有幀都對(duì)齊到第一幀,以達(dá)到視頻消抖問(wèn)題,實(shí)現(xiàn)邏輯如下圖所示。

(1)首先對(duì)視頻進(jìn)行抽第一幀與最后一幀,為什么抽取兩幀?這樣做的主要目的是,我們?cè)谧鰩瑢?duì)齊時(shí),使用幀中靜態(tài)物的關(guān)鍵點(diǎn)做對(duì)齊,如果特征點(diǎn)來(lái)源于動(dòng)態(tài)物上,那么對(duì)齊后就會(huì)產(chǎn)生形變,我們選取第一幀與最后一幀,提取特征點(diǎn),留下交集部分,則可以得到靜態(tài)特征點(diǎn)我們這里稱(chēng)為特征模板,然后將特征模板應(yīng)用到每一幀上,這樣可以做有效對(duì)齊。

(2)常用特征點(diǎn)檢測(cè)器:

SIFT: 04 年提出,廣泛應(yīng)用于各種跟蹤和識(shí)別算法,表現(xiàn)能力強(qiáng),但計(jì)算復(fù)雜度高。

SURF: 06 年提出,是 SIFT 的演進(jìn)版本,保持強(qiáng)表現(xiàn)能力的同時(shí)大大減少了計(jì)算量。

BRISK: BRIEF 的演進(jìn)版本,壓縮了特征的表示,提高了匹配速度。 ORB: 以速度著稱(chēng),是 SURF 的演進(jìn)版本,多用于實(shí)時(shí)應(yīng)用。

GFTT: 最早提出的 Harris 角點(diǎn)的改進(jìn)版本,經(jīng)常合稱(chēng)為 Harris-Shi-Tomasi 角點(diǎn)。

SimpleBlob: 使用 blob 的概念來(lái)抽取圖像中的特征點(diǎn),相對(duì)于角點(diǎn)的一種創(chuàng)新。 FAST: 相比其他方法特征點(diǎn)數(shù)量最多,但也容易得到距離過(guò)近的點(diǎn),需要經(jīng)過(guò) NMS。

Star: 最初用于視覺(jué)測(cè)距,后來(lái)也成為一種通用的特征點(diǎn)檢測(cè)方法。

我們這里使用的是SURF特征點(diǎn)檢測(cè)器

第一幀特特征點(diǎn)提取??????

最后一幀特征點(diǎn)提取

(3)在上圖中,我們發(fā)現(xiàn)所提取的特征點(diǎn)中部分來(lái)自于車(chē)身,由于車(chē)是運(yùn)動(dòng)的,所以我們不能使用,我們用第一幀與最后一幀做靜態(tài)特幀點(diǎn)匹配,生成靜態(tài)特征模板,在下圖中,我們發(fā)現(xiàn)只有所有的特征點(diǎn)只選取在靜態(tài)物上

靜態(tài)特征點(diǎn)模板

(4)靜態(tài)特征模板匹配 ,我們這里使用Flann算法,匹配結(jié)果如下

特征匹配

(5)使用匹配成功的兩組特征點(diǎn),估計(jì)兩幀之間的透視變換 (Perspective Transformation)。估計(jì)矩陣 H,其中 (x_i, y_i) 和 (x_i^′, y_i^′) 分別是兩幀的特征點(diǎn)。

第一幀

最后一幀對(duì)齊到第一幀

四、實(shí)現(xiàn)代碼

運(yùn)行環(huán)境以及版本,安裝命令如下:
python版本:3.X
opencv-python:3.4.2.16
opencv-contrib-python:3.4.2.16

需要卸載之前的opencv-python版本
pip uninstall opencv-python
pip uninstall opencv-contrib-python
 
安裝新的版本
pip install opencv_python==3.4.2.16 
pip install opencv-contrib-python==3.4.2.16

代碼基于python實(shí)現(xiàn),如下所示:

import cv2
import numpy as np
from tqdm import tqdm
import argparse
import os
 
# get param
parser = argparse.ArgumentParser(description='')
parser.add_argument('-v', type=str, default='')  # 指定輸入視頻路徑位置(參數(shù)必選)
parser.add_argument('-o', type=str, default='')  # 指定輸出視頻路徑位置(參數(shù)必選)
parser.add_argument('-n', type=int, default=-1)  # 指定處理的幀數(shù)(參數(shù)可選), 不設(shè)置使用視頻實(shí)際幀
 
# eg: python3 stable.py -v=video/01.mp4 -o=video/01_stable.mp4 -n=100 -p=6
 
args = parser.parse_args()
 
input_path = args.v
output_path = args.o
number = args.n
 
class Stable:
    # 處理視頻文件路徑
    __input_path = None
 
    __output_path = None
 
    __number = number
 
    # surf 特征提取
    __surf = {
        # surf算法
        'surf': None,
        # 提取的特征點(diǎn)
        'kp': None,
        # 描述符
        'des': None,
        # 過(guò)濾后的特征模板
        'template_kp': None
    }
 
    # capture
    __capture = {
        # 捕捉器
        'cap': None,
        # 視頻大小
        'size': None,
        # 視頻總幀
        'frame_count': None,
        # 視頻幀率
        'fps': None,
        # 視頻
        'video': None,
    }
 
    # 配置
    __config = {
        # 要保留的最佳特征的數(shù)量
        'key_point_count': 5000,
        # Flann特征匹配
        'index_params': dict(algorithm=0, trees=5),
        'search_params': dict(checks=50),
        'ratio': 0.5,
    }
 
    # 特征提取列表
    __surf_list = []
 
    def __init__(self):
        pass
 
    # 初始化capture
    def __init_capture(self):
        self.__capture['cap'] = cv2.VideoCapture(self.__video_path)
        self.__capture['size'] = (int(self.__capture['cap'].get(cv2.CAP_PROP_FRAME_WIDTH)),
                                  int(self.__capture['cap'].get(cv2.CAP_PROP_FRAME_HEIGHT)))
 
        self.__capture['fps'] = self.__capture['cap'].get(cv2.CAP_PROP_FPS)
 
        self.__capture['video'] = cv2.VideoWriter(self.__output_path, cv2.VideoWriter_fourcc(*"mp4v"),
                                                  self.__capture['fps'], self.__capture['size'])
 
        self.__capture['frame_count'] = int(self.__capture['cap'].get(cv2.CAP_PROP_FRAME_COUNT))
 
        if number == -1:
            self.__number = self.__capture['frame_count']
        else:
            self.__number = min(self.__number, self.__capture['frame_count'])
 
    # 初始化surf
    def __init_surf(self):
 
        self.__capture['cap'].set(cv2.CAP_PROP_POS_FRAMES, 0)
        state, first_frame = self.__capture['cap'].read()
 
        self.__capture['cap'].set(cv2.CAP_PROP_POS_FRAMES, self.__capture['frame_count'] - 1)
        state, last_frame = self.__capture['cap'].read()
 
        self.__surf['surf'] = cv2.xfeatures2d.SURF_create(self.__config['key_point_count'])
 
        self.__surf['kp'], self.__surf['des'] = self.__surf['surf'].detectAndCompute(first_frame, None)
        kp, des = self.__surf['surf'].detectAndCompute(last_frame, None)
 
        # 快速臨近匹配
        flann = cv2.FlannBasedMatcher(self.__config['index_params'], self.__config['search_params'])
        matches = flann.knnMatch(self.__surf['des'], des, k=2)
 
        good_match = []
        for m, n in matches:
            if m.distance < self.__config['ratio'] * n.distance:
                good_match.append(m)
 
        self.__surf['template_kp'] = []
        for f in good_match:
            self.__surf['template_kp'].append(self.__surf['kp'][f.queryIdx])
 
    # 釋放
    def __release(self):
        self.__capture['video'].release()
        self.__capture['cap'].release()
 
    # 處理
    def __process(self):
 
        current_frame = 1
 
        self.__capture['cap'].set(cv2.CAP_PROP_POS_FRAMES, 0)
 
        process_bar = tqdm(self.__number, position=current_frame)
 
        while current_frame <= self.__number:
            # 抽幀
            success, frame = self.__capture['cap'].read()
 
            if not success: return
 
            # 計(jì)算
            frame = self.detect_compute(frame)
 
            # 寫(xiě)幀
            self.__capture['video'].write(frame)
 
            current_frame += 1
 
            process_bar.update(1)
 
    # 視頻穩(wěn)像
    def stable(self, input_path, output_path, number):
        self.__video_path = input_path
        self.__output_path = output_path
        self.__number = number
 
        self.__init_capture()
        self.__init_surf()
        self.__process()
        self.__release()
 
    # 特征點(diǎn)提取
    def detect_compute(self, frame):
 
        frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
 
        # 計(jì)算特征點(diǎn)
        kp, des = self.__surf['surf'].detectAndCompute(frame_gray, None)
 
        # 快速臨近匹配
        flann = cv2.FlannBasedMatcher(self.__config['index_params'], self.__config['search_params'])
        matches = flann.knnMatch(self.__surf['des'], des, k=2)
 
        # 計(jì)算單應(yīng)性矩陣
        good_match = []
        for m, n in matches:
            if m.distance < self.__config['ratio'] * n.distance:
                good_match.append(m)
 
        # 特征模版過(guò)濾
        p1, p2 = [], []
        for f in good_match:
            if self.__surf['kp'][f.queryIdx] in self.__surf['template_kp']:
                p1.append(self.__surf['kp'][f.queryIdx].pt)
                p2.append(kp[f.trainIdx].pt)
 
        # 單應(yīng)性矩陣
        H, _ = cv2.findHomography(np.float32(p2), np.float32(p1), cv2.RHO)
 
        # 透視變換
        output_frame = cv2.warpPerspective(frame, H, self.__capture['size'], borderMode=cv2.BORDER_REPLICATE)
 
        return output_frame
 
if __name__ == '__main__':
 
    if not os.path.exists(input_path):
        print(f'[ERROR] File "{input_path}" not found')
        exit(0)
    else:
        print(f'[INFO] Video "{input_path}" stable begin')
 
    s = Stable()
    s.stable(input_path, output_path, number)
 
    print('[INFO] Done.')
    exit(0)

參數(shù)說(shuō)明:

-v 指定輸入視頻路徑位置(參數(shù)必選)

-o 指定輸出視頻路徑位置(參數(shù)必選)

-n 指定處理的幀數(shù)(參數(shù)可選), 不設(shè)置使用視頻實(shí)際幀

調(diào)用示例:

python3 stable.py -v=test.mp4 -o=test_stable.mp4

五、效果展示

我們消抖后的視頻道路完全沒(méi)有晃動(dòng),但是在邊界有馬賽克一樣的東西,那是因?yàn)閳D片對(duì)齊后后出現(xiàn)黑邊,我們采用邊緣點(diǎn)重復(fù)來(lái)彌補(bǔ)黑邊。

消抖前

消抖后

六、效率優(yōu)化

目前的處理效率(原視頻尺寸3840*2160),我們可以看出主要時(shí)間是花費(fèi)在特征點(diǎn)(key)提取上。
可以采用異步處理+GPU提高計(jì)算效率

處理效率

到此這篇關(guān)于基于opencv對(duì)高空拍攝視頻消抖處理的文章就介紹到這了,更多相關(guān)opencv視頻消抖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python譜減法語(yǔ)音降噪實(shí)例

    Python譜減法語(yǔ)音降噪實(shí)例

    今天小編就為大家分享一篇Python譜減法語(yǔ)音降噪實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-12-12
  • 玩數(shù)據(jù)必備Python庫(kù)之numpy使用詳解

    玩數(shù)據(jù)必備Python庫(kù)之numpy使用詳解

    NumPy提供了許多高級(jí)的數(shù)值編程工具,如矩陣數(shù)據(jù)類(lèi)型、矢量處理,以及精密的運(yùn)算庫(kù),下面這篇文章主要給大家介紹了關(guān)于玩數(shù)據(jù)必備Python庫(kù)之numpy使用的相關(guān)資料,需要的朋友可以參考下
    2022-02-02
  • Python利用socket模塊開(kāi)發(fā)簡(jiǎn)單的端口掃描工具的實(shí)現(xiàn)

    Python利用socket模塊開(kāi)發(fā)簡(jiǎn)單的端口掃描工具的實(shí)現(xiàn)

    這篇文章主要介紹了Python利用socket模塊開(kāi)發(fā)簡(jiǎn)單的端口掃描工具的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • python爬蟲(chóng) execjs安裝配置及使用

    python爬蟲(chóng) execjs安裝配置及使用

    這篇文章主要介紹了python爬蟲(chóng) execjs安裝配置及使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • 在 Python 中解析 ISO 8601 日期的詳細(xì)過(guò)程

    在 Python 中解析 ISO 8601 日期的詳細(xì)過(guò)程

    這篇文章主要介紹了在 Python 中解析 ISO 8601 日期,我們將討論典型的 ISO 8601 日期的結(jié)構(gòu),并向您展示如何將典型的 DateTime 對(duì)象解析為可以在所有地方使用的標(biāo)準(zhǔn)化 DateTime,需要的朋友可以參考下
    2023-08-08
  • 快速進(jìn)修Python指南之控制if-else循環(huán)技巧

    快速進(jìn)修Python指南之控制if-else循環(huán)技巧

    這篇文章主要為大家介紹了Java開(kāi)發(fā)者的Python快速進(jìn)修指南之控制之if-else和循環(huán)技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Python的Random庫(kù)的使用方法詳解

    Python的Random庫(kù)的使用方法詳解

    這篇文章主要介紹了Python的Random庫(kù)的使用方法詳解,random庫(kù)是使用隨機(jī)數(shù)的Python標(biāo)準(zhǔn)庫(kù),python中用于生成偽隨機(jī)數(shù)的函數(shù)庫(kù)是random,需要的朋友可以參考下
    2023-07-07
  • Python中的閉包

    Python中的閉包

    這篇文章主要介紹了Python中的閉包,閉包在函數(shù)中提出的概念,簡(jiǎn)單來(lái)說(shuō)就是一個(gè)函數(shù)定義中引用了函數(shù)外定義的變量,并且該函數(shù)可以在其定義環(huán)境外被執(zhí)行。這樣的一個(gè)函數(shù)我們稱(chēng)之為閉包,下面我們一起來(lái)看看文章內(nèi)容的具體介紹
    2021-11-11
  • Python實(shí)現(xiàn)KNN(K-近鄰)算法的示例代碼

    Python實(shí)現(xiàn)KNN(K-近鄰)算法的示例代碼

    這篇文章主要介紹了Python實(shí)現(xiàn)KNN(K-近鄰)算法的示例代碼,它主要用于對(duì)事物進(jìn)行分類(lèi)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-03-03
  • IPython庫(kù)中的display函數(shù)的簡(jiǎn)介、使用方法、應(yīng)用案例詳細(xì)攻略

    IPython庫(kù)中的display函數(shù)的簡(jiǎn)介、使用方法、應(yīng)用案例詳細(xì)攻略

    display 函數(shù)可以接受一個(gè)或多個(gè)參數(shù),每個(gè)參數(shù)都是一個(gè) Python 對(duì)象。它會(huì)自動(dòng)根據(jù)對(duì)象的類(lèi)型選擇合適的顯示方式,并在 Jupyter Notebook 中顯示出來(lái),這篇文章主要介紹了IPython庫(kù)中的display函數(shù)的簡(jiǎn)介、使用方法、應(yīng)用案例詳細(xì)攻略,需要的朋友可以參考下
    2023-04-04

最新評(píng)論

乃东县| 呼伦贝尔市| 财经| 东城区| 常熟市| 望城县| 苍梧县| 镇安县| 五常市| 海宁市| 寿光市| 利津县| 垦利县| 苏尼特左旗| 内黄县| 封丘县| 合肥市| 徐州市| 高阳县| 汉中市| 玉林市| 东莞市| 闸北区| 墨江| 咸阳市| 三亚市| 同江市| 英超| 犍为县| 宁安市| 泾阳县| 赣榆县| 遵义县| 达拉特旗| 沙坪坝区| 明溪县| 金昌市| 嘉荫县| 湛江市| 石泉县| 肃宁县|