覆盆子pi:校准相机和图像的不失真 [英] Raspberry pi:calibrate camera and undistortion of image

查看:2098
本文介绍了覆盆子pi:校准相机和图像的不失真的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从图像中删除鱼眼效果,所以我需要相机矩阵和失真高效。这就是为什么我创建了 cal.py 文件。



当我运行那个文件它给我相机矩阵和失真效率我必须在 undist.py 文件中解除图像。现在每次我得到相同的RMS,相机矩阵,失真系数如附图所示(输出)。



把这个参数放在undist.py文件中,这是给我空白图像..如何解决这个问题?PLz帮助我...感谢在advance.i有捕获8图像和一个棋盘模式的示例图像如下图所示。



这是我的cal.py和undist.py文件:






cal.py



 #!/ usr / bin / env python 
import numpy as np
import cv2
import cv
import os
从公共导入splitfn
USAGE ='''USAGE:calib.py [ - -save< filename>] [--debug< output path>] [--square_size] [< image mask>]'''
if __name__ =='__main__':
import sys ,getopt
from glob import glob
camera_matrix = cv.CreateMat(3,3,cv.CV_32FC1)
dist_coefs = cv.CreateMat(4,1,cv.CV_32FC1)
args,img_mask = getopt.getopt(sys.argv [1:],'',['save =','debug =','square_size ='])
args = dict(args)
img_mask ='image * .jpg'
img_names = glob(img_mask)
debug_dir = args.get(' - debug')
square_size = float(args.get(' - square_size ',1.0))
pattern_size =(9,6)
pattern_points = np.zeros((np.prod(pattern_size),3),np.float32)
pattern_points [:, 2] = np.indices(pattern_size).T.reshape(-1,2)
pattern_points * = square_size
obj_points = []
img_points = []
h,w = 0,0
for img_names中的fn:
print'processing%s ...'%fn,
img = cv2.imread(fn,0)
h,w = img .shape [:2]
found,corners = cv2.findChessboardCorners(img,pattern_size)
如果找到:
term =(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT,30,0.1)
cv2.cornerSubPix(img,corner,(5,5),(-1,-1),term)
如果debug_dir:
vis = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
cv2.drawChessboardCorners(vis,pattern_size,corner,found)
path,name,ext = splitfn(fn)
cv2.imwrite('%s /%s_chess.png'%(debug_dir, name),vis)
如果没有找到:
print'chessboard not found'
continue
img_points.append(corners.reshape(-1,2))
obj_points.append(pattern_points)
print'ok'
rms,camera_matrix,dist_coefs,rvecs,tvecs = cv2.calibrateCamera(obj_points,img_points,(w,h))
print ,rms
printcamera matrix:\\\
,camera_matrix
printdistortion coefficients:,dist_coefs.ravel()
cv2.destroyAllWindows()






undist.py



 #!/ usr / bin / env python 
import smtplib
导入时间
import subprocess
来自email.MIMEMultipart import MIMEMultipart
从email.MIMEBase导入MIMEBase
从email.MIMEText导入MIMEText
从email.MIMEImage导入MIMEImage
导入RPi.GPIO为GPIO
导入映像
导入cv2
import numpy as np

#定义这些一次;使用它们两次!
strFrom ='user.example@gmail.com'
strTo ='user.example@gmail.com'

#create email
#创建根消息并填写from,to和subj $
msgRoot = MIMEMultipart()
msgRoot ['Subject'] ='fisheye到正常图像'
msgRoot ['From'] = strFrom
msgRoot ['To'] = strTo


GPIO.setmode(GPIO.BCM)
GPIO.setup(4,GPIO.IN)
print 按钮发送电子邮件
GPIO.setup(4,GPIO.IN,pull_up_down = GPIO.PUD_UP)
while True:
input = GPIO.input(4)
if input == False:
printbutton pressed
subprocess.Popen([fswebcam, - r 640x480,image4.jpg])
time.sleep )
#将参数复制到数组
K = np.array([[271.40850489,0,306.38705314],[0,271.08688021,234.03565551],[0,0,1]])
d = np.array ([-3.55461489e-01,1.45402260e-01,-1.33385142e-03,1.63603888e-04,-2.96650946e-02])#只使用前两个术语(无翻译)

#读取您的一个图片
img = cv2.imread(image4.jpg)
h,w = img.shape [:2]

#undistort
newcamera ,roi = cv2.getOptimalNewCameraMatrix(K,d,(w,h),0)
newimg = cv2.undistort(img,K,d,None,newcamera)

cv2.imwrite (original.jpg,img)
cv2.imwrite(undistorted.jpg,newimg)


#此示例假定映像位于当前目录
#fp = open('image4.jpg','rb')
#msgImage = MIMEImage(fp.read())
#fp.close()
#msgRoot.attach (msgImage)
#send mail
#s = smtplib.SMTP('smtp.gmail.com',587)
#s.starttls()
#s.login 'user.example@gmail.com','password')
#s.sendmail(strFrom,strTo,plt.show())
#s.close()
print发送
time.sleep(0.2)

这是我的输入图片:



这是我的输出图片:

解决方案

我会做一个答案来总结评论中解决的所有问题(这种方式,未来的读者不必阅读所有的)


  1. 按照教学课程此处,以更好地了解您应该做什么以及使用哪些功能。


  2. 检查您的相机矩阵是否具有正确的形式:

      [f_x s c_x 
    0 f_y c_y
    0 0 1]

    确保每一步都要正确加载图片,并确保图片正确无误(使用<$ c $


    pre> newcamera,roi = cv2.getOptimalNewCameraMatrix(K,d,(w,h),0)
    newimg = cv2.undistort(img,K,d,None,newcamera )


为什么,从opencv 文档,我们有:

  cv2.getOptimalNewCameraMatrix(cameraMatrix,distCoeffs,imageSize,alpha [,newImgSize [,centerPrincipalPoint]])→retval,validPixROI 


该函数计算并返回基于自由缩放参数的
的最佳新相机矩阵。通过改变这个参数,你可以
只检索敏感的像素alpha = 0,保持所有的原始图像
像素如果有有价值的信息在角落alpha = 1或
之间的东西。当α> 0时,非失真结果是
可能具有对应于所捕获的失真图像之外的虚拟像素
的一些黑色像素。原始的相机矩阵
失真系数,计算的新相机矩阵和
newImageSize应该传递给initUndistortRectifyMap()以产生
remap()的映射。


这意味着新的相机矩阵也给你一个新的有效的大小!更具体地说:


计算的新相机矩阵,newImageSize应传递给initUndistortRectifyMap()


但是undistort函数会自动执行 initUndistortRectifyMap ...并且没有办法传递 newImageSize 。因此,基本上你有两个选项。


  1. 使用 newcamera 矩阵,执行 undistort ,则应手动执行所有操作....这意味着您必须执行 initUndistortRectifyMap remap <

  2. 使用 calibrateCamera 功能。这种方式不会有此缩放效果,但您可能会有一些额外的黑色像素代表因修正而无法看到的区域。

如果没有,它将总是给你这种缩放效果,因为它不会显示未失真区域的无效像素(黑色像素)。


I want to remove fisheye effect from image, so I need camera matrix and distortion cofficient. That's why I created cal.py file.

When I run that file it give me camera matrix and distortion efficient which I have to put in undist.py file to undistort the image. now every time i got the same RMS,camera matrix,distortion coefficient as shown in attached image(output).

but when i put this parameters in undist.py file that is give me blank image.. how to solve this problem?PLz help me...Thanks in advance.i have capture 8 image and one of the sample image of chessboard pattern shown in below image.

This is my cal.py and undist.py file:


cal.py

#!/usr/bin/env python
import numpy as np
import cv2
import cv
import os
from common import splitfn
USAGE = ''' USAGE: calib.py [--save <filename>] [--debug <output path>] [--square_size] [<image mask>] '''
if __name__ == '__main__':
    import sys, getopt
    from glob import glob
    camera_matrix = cv.CreateMat(3, 3, cv.CV_32FC1)
    dist_coefs = cv.CreateMat(4, 1, cv.CV_32FC1)
    args, img_mask = getopt.getopt(sys.argv[1:], '', ['save=', 'debug=', 'square_size='])
    args = dict(args)
    img_mask = 'image*.jpg'
    img_names = glob(img_mask)
    debug_dir = args.get('--debug')
    square_size = float(args.get('--square_size', 1.0))
    pattern_size = (9, 6)
    pattern_points = np.zeros( (np.prod(pattern_size), 3), np.float32 )
    pattern_points[:,:2] = np.indices(pattern_size).T.reshape(-1, 2)
    pattern_points *= square_size
    obj_points = []
    img_points = []
    h, w = 0, 0
    for fn in img_names:
        print 'processing %s...' % fn,
        img = cv2.imread(fn, 0)
        h, w = img.shape[:2]
        found, corners = cv2.findChessboardCorners(img, pattern_size)
        if found:
            term = ( cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.1 )
            cv2.cornerSubPix(img, corners, (5, 5), (-1, -1), term)
        if debug_dir:
            vis = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
            cv2.drawChessboardCorners(vis, pattern_size, corners, found)
            path, name, ext = splitfn(fn)
            cv2.imwrite('%s/%s_chess.png' % (debug_dir, name), vis)
        if not found:
            print 'chessboard not found'
            continue
        img_points.append(corners.reshape(-1, 2))
        obj_points.append(pattern_points)
        print 'ok'
    rms, camera_matrix, dist_coefs, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, (w, h))
    print "RMS:", rms
    print "camera matrix:\n", camera_matrix
    print "distortion coefficients: ", dist_coefs.ravel()
    cv2.destroyAllWindows()


undist.py

#!/usr/bin/env python
import smtplib
import time
import subprocess
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
import RPi.GPIO as GPIO
import Image
import cv2
import numpy as np

# Define these once; use them twice!
strFrom = 'user.example@gmail.com'
strTo = 'user.example@gmail.com'

#create email
# Create the root message and fill in the from, to, and subj$
msgRoot = MIMEMultipart()
msgRoot['Subject'] = 'fisheye to normal image'
msgRoot['From'] = strFrom
msgRoot['To'] = strTo


GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.IN)
print "press button to send email"
GPIO.setup(4,GPIO.IN,pull_up_down=GPIO.PUD_UP)
while True:
        input=GPIO.input(4)
        if input == False:
                print "button pressed"
                subprocess.Popen(["fswebcam","-r 640x480", "image4.jpg"])
                time.sleep(5)
                # copy parameters to arrays
                K = np.array([[ 271.40850489,0,306.38705314],[0,271.08688021 , 234.03565551],[0,0,1]])
                d = np.array( [ -3.55461489e-01 ,  1.45402260e-01 , -1.33385142e-03  , 1.63603888e-04,  -2.96650946e-02]) # just use first two terms (no translation)

                # read one of your images
                img = cv2.imread("image4.jpg")
                h, w = img.shape[:2]

                # undistort
                newcamera, roi = cv2.getOptimalNewCameraMatrix(K, d, (w,h), 0)
                newimg = cv2.undistort(img, K, d, None, newcamera)

                cv2.imwrite("original.jpg", img)
                cv2.imwrite("undistorted.jpg", newimg)


                # This example assumes the image is in the current directory
                #fp = open('image4.jpg', 'rb')
                #msgImage = MIMEImage(fp.read())
                #fp.close()
                #msgRoot.attach(msgImage)
                # send mail
                #s = smtplib.SMTP('smtp.gmail.com',587)
                #s.starttls()
                #s.login('user.example@gmail.com' , 'password')
                #s.sendmail(strFrom, strTo, plt.show())
                #s.close()
                print "Email sent"
                time.sleep(0.2)

This is my input image:

This is my output image:

解决方案

I will do an answer to summarize all the problems solved in the comments (this way the future readers do not have to read all of them).

  1. Follow the tutorial from here to have a better understanding of what you should do and which functions to use.

  2. Check that your camera matrix have the correct form:

    [ f_x  s    c_x
      0    f_y  c_y
      0    0    1  ]
    

    the s is a skew value that I think in opencv it always gives 0.

  3. Make sure in every step that the images are loading correctly and that they are doing exactly what is intended (use imshow function to debug)

  4. This part of your code

    newcamera, roi = cv2.getOptimalNewCameraMatrix(K, d, (w,h), 0)
    newimg = cv2.undistort(img, K, d, None, newcamera)
    

is faulty. Why, well from the opencv documentation we have that:

cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, alpha[, newImgSize[, centerPrincipalPoint]]) → retval, validPixROI

and

The function computes and returns the optimal new camera matrix based on the free scaling parameter. By varying this parameter, you may retrieve only sensible pixels alpha=0 , keep all the original image pixels if there is valuable information in the corners alpha=1 , or get something in between. When alpha>0 , the undistortion result is likely to have some black pixels corresponding to "virtual" pixels outside of the captured distorted image. The original camera matrix, distortion coefficients, the computed new camera matrix, and newImageSize should be passed to initUndistortRectifyMap() to produce the maps for remap() .

This means that the new camera matrix also gives you a new valid size!! To be more specifically:

the computed new camera matrix, and newImageSize should be passed to initUndistortRectifyMap()

But the undistort function does the initUndistortRectifyMap automatically.... and it doesn't have a way to pass the newImageSize from this function. So basically you have 2 options.

  1. Use your newcamera matrix, but instead of doing undistort, you should do everything manually.... this means that you must do initUndistortRectifyMap and remap using the new sizes and new camera matrix.
  2. Use the original camera matrix obtained in the calibrateCamera function. This way it will not have this zoom effect, but you may have some extra black pixels representing the areas that you may not see due to rectification.

If not, it will always give you this zoom effect, because it will not show the invalid pixels (black pixels) of the undistorted areas.

这篇关于覆盆子pi:校准相机和图像的不失真的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆