<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          使用OpenCV實(shí)現(xiàn)哈哈鏡效果

          共 6827字,需瀏覽 14分鐘

           ·

          2020-09-09 17:05


          點(diǎn)擊上方小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂

          重磅干貨,第一時(shí)間送達(dá)

          我們都記得那些曾經(jīng)去游樂園或縣集市的童年時(shí)代。這些游樂園中我最喜歡的是哈哈鏡室。


          有趣的鏡子不是平面鏡子,而是凸/凹反射表面的組合,它們會(huì)產(chǎn)生扭曲效果,當(dāng)我們?cè)谶@些鏡子前面移動(dòng)時(shí),這些效果看起來很有趣。


          在本文中,我們將學(xué)習(xí)使用OpenCV創(chuàng)建屬于自己的哈哈鏡。


          視頻


          我們可以看到上面視頻中的孩子如何享受不同的有趣鏡子。我們都想擁有這樣的樂趣,但是為此,我們必須在現(xiàn)實(shí)中找到一面哈哈鏡。


          現(xiàn)在,我們無需去哈哈鏡室即可在家中享受這種有趣的效果。在本文中,我們將學(xué)習(xí)如何使用OpenCV制作這些有趣的鏡子的數(shù)字版本。我們先來看一下具體的效果。


          視頻


          圖像形成理

          我們首先需要了解如何將世界上的3D點(diǎn)投影到相機(jī)的圖像坐標(biāo)系中,這部分內(nèi)容我們默認(rèn)小伙伴們已經(jīng)了解,如果不了解,可以簡(jiǎn)單搜索一下,會(huì)有很多講解的文章。這里我們只做一個(gè)簡(jiǎn)單的介紹。


          世界坐標(biāo)中的3D點(diǎn)和圖像中的像素點(diǎn)具有以下等式映射關(guān)系。其中P是相機(jī)投影矩陣。

          項(xiàng)目的主要內(nèi)容

          整個(gè)項(xiàng)目可以分為三個(gè)主要步驟:

          1. 創(chuàng)建一個(gè)虛擬相機(jī)。
          2. 定義3D表面(鏡面),并使用合適的投影矩陣值將其投影到虛擬相機(jī)中。
          3. 使用3D曲面的投影點(diǎn)的圖像坐標(biāo)來應(yīng)用基于網(wǎng)格的變形以獲得有趣的鏡子的所需效果。

          下圖可能會(huì)幫助我們更好地理解步驟。

          圖1:創(chuàng)建數(shù)字滑稽鏡像所涉及的步驟。創(chuàng)建一個(gè)3D表面,即鏡子(左),在虛擬相機(jī)中捕獲平面以獲取相應(yīng)的2D點(diǎn),使用獲得的2D點(diǎn)將基于網(wǎng)格的變形應(yīng)用于圖像,從而產(chǎn)生類似于滑稽鏡子的效果。


          接下來我們將詳細(xì)的介紹每一個(gè)步驟


          創(chuàng)建一個(gè)虛擬相機(jī)

          基于上述理論,我們清楚地知道3D點(diǎn)如何與其對(duì)應(yīng)的圖像坐標(biāo)相關(guān)。現(xiàn)在讓我們了解虛擬相機(jī)的含義以及如何使用該虛擬相機(jī)捕獲圖像。


          虛擬相機(jī)本質(zhì)上是矩陣P,因?yàn)樗嬖V我們3D世界坐標(biāo)與相應(yīng)圖像像素坐標(biāo)之間的關(guān)系。讓我們看看如何使用python創(chuàng)建虛擬相機(jī)。


          我們將首先創(chuàng)建外部參數(shù)矩陣(M1)和內(nèi)部參數(shù)矩陣(K),然后使用它們創(chuàng)建相機(jī)投影矩陣(P)。

          import numpy as np
          # Defining the translation matrix# Tx,Ty,Tz represent the position of our virtual camera in the world coordinate systemT = np.array([[1,0,0,-Tx],[0,1,0,-Ty],[0,0,1,-Tz]])
          # Defining the rotation matrix # alpha,beta,gamma define the orientation of the virtual camera
          Rx = np.array([[1, 0, 0], [0, math.cos(alpha), -math.sin(alpha)], [0, math.sin(alpha), math.cos(alpha)]])
          Ry = np.array([[math.cos(beta), 0, -math.sin(beta)],[0, 1, 0],[math.sin(beta),0,math.cos(beta)]])
          Rz = np.array([[math.cos(gamma), -math.sin(gamma), 0],[math.sin(gamma),math.cos(gamma), 0],[0, 0, 1]])
          R = np.matmul(Rx, np.matmul(Ry, Rz))
          # Calculating the extrinsic camera parameter matrix M1M1 = np.matmul(R,T)
          # Calculating the intrinsic camera parameter matrix K# sx and sy are apparent pixel length in x and y direction# ox and oy are the coordinates of the optical center in the image plane.K = np.array([[-focus/sx,sh,ox],[0,focus/sy,oy],[0,0,1]])
          P = np.matmul(K,RT)


          請(qǐng)注意,我們必須為上面矩陣中的所有參數(shù)設(shè)置合適的值,例如focus,sx,sy,ox,oy等。


          那么,我們?nèi)绾斡眠@個(gè)虛擬相機(jī)捕捉圖像呢?


          首先,我們假設(shè)原始圖像或視頻幀是3D平面。當(dāng)然,我們知道場(chǎng)景實(shí)際上不是3D平面,但是我們沒有圖像中每個(gè)像素的深度信息。因此,我們僅假設(shè)場(chǎng)景為平面。請(qǐng)記住,我們的目標(biāo)不是為了科學(xué)目的而準(zhǔn)確地為滑稽的鏡子建模。我們只是想將其近似用于娛樂。


          其次,我們將圖像定義為3D平面,我們可以簡(jiǎn)單地將矩陣P與世界坐標(biāo)相乘并獲得像素坐標(biāo)(u,v)。應(yīng)用此轉(zhuǎn)換與使用我們的虛擬相機(jī)捕獲3D點(diǎn)的圖像相同!


          我們?nèi)绾未_定捕獲圖像中像素的顏色?場(chǎng)景中物體的材質(zhì)屬性如何?


          在渲染逼真的3D場(chǎng)景時(shí),以上所有這些點(diǎn)絕對(duì)重要,但是我們不必渲染逼真的場(chǎng)景。我們只是想做一些看起來很有趣的事情。


          我們需要做的就是捕獲(投影),首先將原始圖像(或視頻幀)表示為虛擬相機(jī)中的3D平面,然后使用投影矩陣將該平面上的每個(gè)點(diǎn)投影到虛擬相機(jī)的圖像平面上。


          我們將3D坐標(biāo)存儲(chǔ)為numpy數(shù)組(W),將相機(jī)矩陣存儲(chǔ)為numpy數(shù)組(P),然后執(zhí)行矩陣乘法P * W捕獲3D點(diǎn)。


          但是,在編寫代碼以使用虛擬相機(jī)捕獲3D表面之前,我們首先需要定義3D表面。


          定義3D表面(鏡子)

          為了定義3D曲面,我們形成X和Y坐標(biāo)的網(wǎng)格,然后針對(duì)每個(gè)點(diǎn)計(jì)算Z坐標(biāo)作為X和Y的函數(shù)。因此,對(duì)于平面鏡,我們將定義Z = K,其中K為任何常數(shù)。下圖顯示了可以生成的鏡面的一些示例。

          3D表面的一些示例可用于創(chuàng)建哈哈鏡鏡子

          現(xiàn)在,由于我們對(duì)如何定義3D曲面并將其捕獲到虛擬相機(jī)中有了清晰的思路,讓我們看看如何在python中進(jìn)行程序書寫。

          # Determine height and width of input imageH,W = image.shape[:2]# Define x and y coordinate values in range (-W/2 to W/2) and (-H/2 to H/2) respectively
          x = np.linspace(-W/2, W/2, W)y = np.linspace(-H/2, H/2, H)
          # Creating a mesh grid using the x and y coordinate range defined above.xv,yv = np.meshgrid(x,y)
          # Generating the X,Y and Z coordinates of the plane # Here we define Z = 1 planeX = xv.reshape(-1,1)Y = yv.reshape(-1,1)Z = X*0+1 # The mesh will be located on Z = 1 plane
          pts3d = np.concatenate(([X],[Y],[Z],[X*0+1]))[:,:,0]
          pts2d = np.matmul(P,pts3d)u = pts2d[0,:]/(pts2d[2,:]+0.00000001)v = pts2d[1,:]/(pts2d[2,:]+0.00000001)


          VCAM:虛擬攝像機(jī)

          我們是否需要每次編寫以上代碼?如果我們想動(dòng)態(tài)更改攝像機(jī)的某些參數(shù)怎么辦?為了簡(jiǎn)化創(chuàng)建此類3D曲面,定義虛擬相機(jī),設(shè)置所有參數(shù)并查找其投影的任務(wù),我們可以使用一個(gè)名為vcam的python庫。我們可以在其文檔中找到使用此庫的不同方式的各種插圖。它減少了我們每次創(chuàng)建虛擬相機(jī),定義3D點(diǎn)和查找2D投影的工作。此外,該庫還負(fù)責(zé)設(shè)置適當(dāng)?shù)膬?nèi)在和外在參數(shù)值,并處理各種異常,從而使其易于使用。存儲(chǔ)庫中還提供了安裝庫的說明。

          我們可以使用pip安裝該庫。

          pip3 install vcam

          下面是我們可以使用該庫編寫代碼的方式,該代碼的工作方式與我們到目前為止編寫的代碼類似,但只有幾行。

          import cv2import numpy as npimport mathfrom vcam import vcam,meshGen
          # Create a virtual camera object. Here H,W correspond to height and width of the input image frame.c1 = vcam(H=H,W=W)
          # Create surface objectplane = meshGen(H,W)
          # Change the Z coordinate. By default Z is set to 1# We generate a mirror where for each 3D point, its Z coordinate is defined as Z = 10*sin(2*pi[x/w]*10)plane.Z = 10*np.sin((plane.X/plane.W)*2*np.pi*10)
          # Get modified 3D points of the surfacepts3d = plane.getPlane()
          # Project the 3D points and get corresponding 2D image coordinates using our virtual camera object c1pts2d = c1.project(pts3d)


          可以很容易地看到vcam庫如何使定義虛擬攝像機(jī),創(chuàng)建3D平面以及將其投影到虛擬攝像機(jī)中變得容易。


          現(xiàn)在可以將投影的2D點(diǎn)用于基于網(wǎng)格的重新映射。這是創(chuàng)建哈哈鏡鏡面效果的最后一步。


          圖像重映射

          重映射基本上是通過將輸入圖像的每個(gè)像素從其原始位置移動(dòng)到由重映射功能定義的新位置來生成新圖像。因此,在數(shù)學(xué)上可以這樣寫:

          上面的方法稱為前向重映射或前向扭曲,其中map_x和map_y函數(shù)為我們提供了像素的新位置,該位置最初位于(x,y)。


          現(xiàn)在,如果map_x和map_y沒有為我們給定的(x,y)對(duì)提供整數(shù)值怎么辦?我們基于最接近的整數(shù)值將(x,y)處的像素強(qiáng)度擴(kuò)展到相鄰像素。這會(huì)在重新映射或生成的圖像中創(chuàng)建孔,這些像素的強(qiáng)度未知且設(shè)置為0。如何避免這些孔?


          我們使用反翹曲。這意味著現(xiàn)在map_x和map_y將為我們提供源圖像中目標(biāo)圖像中給定像素位置(x,y)的舊像素位置。它可以用數(shù)學(xué)方式表示如下:

          我們現(xiàn)在知道如何執(zhí)行重新映射。為了產(chǎn)生有趣的鏡像效果,我們將對(duì)原始輸入幀應(yīng)用重新映射。但是為此,我們需要map_x和map_y。在這種情況下,我們?nèi)绾味xmap_x和map_y?


          相當(dāng)于我們理論解釋中的(u,v)的2D投影點(diǎn)(pts2d)是可以傳遞給remap函數(shù)的所需地圖。現(xiàn)在,讓我們來看一下從投影的2D點(diǎn)提取地圖并應(yīng)用remap函數(shù)(基于網(wǎng)格的變形)以生成有趣的鏡像效果的代碼。

          # Get mapx and mapy from the 2d projected pointsmap_x,map_y = c1.getMaps(pts2d)
          # Applying remap function to input image (img) to generate the funny mirror effectoutput = cv2.remap(img,map_x,map_y,interpolation=cv2.INTER_LINEAR)
          cv2.imshow("Funny mirror",output)cv2.waitKey(0)


          輸入和相應(yīng)的輸出圖像,顯示了基于正弦函數(shù)的滑稽鏡的效果


          太棒了!讓我們嘗試再創(chuàng)建一個(gè)有趣的鏡像,以獲得更好的效果。之后,我們將可以制作自己的有趣的鏡子。

          import cv2import numpy as npimport mathfrom vcam import vcam,meshGen
          # Reading the input image. Pass the path of image you would like to use as input image.img = cv2.imread("chess.png")H,W = img.shape[:2]
          # Creating the virtual camera objectc1 = vcam(H=H,W=W)
          # Creating the surface objectplane = meshGen(H,W)
          # We generate a mirror where for each 3D point, its Z coordinate is defined as Z = 20*exp^((x/w)^2 / 2*0.1*sqrt(2*pi))
          plane.Z += 20*np.exp(-0.5*((plane.X*1.0/plane.W)/0.1)**2)/(0.1*np.sqrt(2*np.pi))pts3d = plane.getPlane()
          pts2d = c1.project(pts3d)map_x,map_y = c1.getMaps(pts2d)
          output = cv2.remap(img,map_x,map_y,interpolation=cv2.INTER_LINEAR)
          cv2.imshow("Funny Mirror",output)cv2.imshow("Input and output",np.hstack((img,output)))cv2.waitKey(0)



          現(xiàn)在我們知道,通過將Z定義為X和Y的函數(shù),我們可以創(chuàng)建不同類型的失真效果。讓我們使用上面的代碼創(chuàng)建更多的效果。我們只需要更改將Z定義為X和Y的函數(shù)的行即可。這將進(jìn)一步幫助您創(chuàng)建自己的效果。


          # We generate a mirror where for each 3D point, its Z coordinate is defined as Z = 20*exp^((y/h)^2 / 2*0.1*sqrt(2*pi))
          plane.Z += 20*np.exp(-0.5*((plane.Y*1.0/plane.H)/0.1)**2)/(0.1*np.sqrt(2*np.pi))



          # We generate a mirror where for each 3D point, its Z coordinate is defined as Z = 20*[ sin(2*pi*(x/w-1/4))) + sin(2*pi*(y/h-1/4))) ]
          plane.Z += 20*np.sin(2*np.pi*((plane.X-plane.W/4.0)/plane.W)) + 20*np.sin(2*np.pi*((plane.Y-plane.H/4.0)/plane.H))



          # We generate a mirror where for each 3D point, its Z coordinate is defined as Z = -100*sqrt[(x/w)^2 + (y/h)^2]
          plane.Z -= 100*np.sqrt((plane.X*1.0/plane.W)**2+(plane.Y*1.0/plane.H)**2)



          項(xiàng)目源碼:https://github.com/spmallick/learnopencv/tree/master/FunnyMirrors



          流群


          歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三?+?上海交大?+?視覺SLAM“。請(qǐng)按照格式備注,否則不予通過。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~


          瀏覽 126
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  玉米地一级婬片A片 | 亚洲女人天堂AV | 综合色导航 | 欧美三级高清在线观看 | 牛牛影视av |