Automatic camera and DPI calibration

General discussion about software packages and releases, new software you've found, and threads by programmers and script writers.

Automatic camera and DPI calibration

Postby og200 » 13 Apr 2012, 10:01

I've just put together some auto-calbiration code (it will eventually go in ScanManager) -- the results look good to my untrained eye and it certainly seems to go a good job on keystoning and minor lens distortion. It also spits out the exact DPI based on the known dimensions of the test pattern of course.

The process is entirely hands off: you feed it a calibration image (a pic of a chessboard pattern) and it does the rest.

Here's the code (Python 2.7 + OpenCV 2.3 + NumPy):

Code: Select all
import cv, cv2
import numpy as np

nBoards = 1
boardWidth = 25
boardHeight = 17
nCorners = boardWidth*boardHeight
boardSize = (boardWidth,boardHeight)
successes = 0


def findCorners(image):
   grayImage = cv2.cvtColor(image,cv.CV_BGR2GRAY)
   
   # find chessboard corners
   (found,corners) = cv2.findChessboardCorners(
      image = grayImage,
      patternSize = boardSize,
      flags = cv2.CALIB_CB_ADAPTIVE_THRESH|cv2.CALIB_CB_FILTER_QUADS|cv2.CALIB_CB_FAST_CHECK
   )
   
   # refine corner locations
   cv2.cornerSubPix(
      image = grayImage, 
      corners = corners, 
      winSize = (11,11), 
      zeroZone = (-1,-1),
      criteria = (cv.CV_TERMCRIT_EPS|cv.CV_TERMCRIT_ITER,30,0.1) 
   )
   
   return corners   
   

def correctDistortion(image):
   
   size = image.shape[1],image.shape[0]
   
   corners = findCorners(image)

   patternPoints = np.zeros( (np.prod(boardSize), 3), np.float32 )
   patternPoints[:,:2] = np.indices(boardSize).T.reshape(-1, 2)
   
   imagePoints = np.array([corners.reshape(-1, 2)])
   objectPoints = np.array([patternPoints])
   cameraMatrix = np.zeros((3, 3))
   distCoefs = np.zeros(4)
   rc,cameraMatrix,distCoeffs,rvecs,tvecs = cv2.calibrateCamera(
      objectPoints,
      imagePoints,
      boardSize,
      cameraMatrix,
      distCoefs
   )
   
   newCameraMatrix,newExtents = cv2.getOptimalNewCameraMatrix(cameraMatrix,distCoeffs,size,0.0)
   
   mapx, mapy = cv2.initUndistortRectifyMap(
      cameraMatrix,
      distCoeffs,
      None,
      cameraMatrix,
      size,
      cv2.CV_32FC1
   )
   newImage = cv2.remap( image, mapx, mapy, cv2.INTER_LANCZOS4 )
   return newImage


def getOuterPoints(rcCorners):
   tl = rcCorners[0,0]
   tr = rcCorners[0,-1]
   bl = rcCorners[-1,0]
   br = rcCorners[-1,-1]
   if tl[0] > tr[0]:
      tr,tl = tl,tr
      br,bl = bl,br
   if tl[1] > bl[1]:
      bl,tl=tl,bl
      br,tr=tr,br
   return (tl,tr,bl,br)


def correctPerspective(image):
   
   size = image.shape[1],image.shape[0]
   
   corners = findCorners(image)

   # visualise the chessboard corners onto the image
   annotatedImage = image.copy()
   cv2.drawChessboardCorners(annotatedImage,boardSize,corners,1)
   cv2.imwrite('annotated.jpg',annotatedImage)
   
   rcCorners = corners.reshape(boardHeight,boardWidth,2)
   # now a 3-d array -- a row is new[x] and a column is new [:,x]
   
   # find top left corner point and bottom right corner point (NOT the same as min/max x and y):
   outerPoints = getOuterPoints(rcCorners)
   tl,tr,bl,br = outerPoints
   
   patternSize = np.array([
      np.sqrt(((tr - tl)**2).sum(0)),
      np.sqrt(((bl - tl)**2).sum(0)),
   ])
   
   inQuad = np.array(outerPoints,np.float32)
   
   outQuad = np.array([
      tl,
      tl + np.array([patternSize[0],0.0]),
      tl + np.array([0.0,patternSize[1]]),
      tl + patternSize,
   ],np.float32)
   
   transform = cv2.getPerspectiveTransform(inQuad,outQuad)
   transformed = cv2.warpPerspective(image,transform,size)

   # calculate DPI for the transformed image
   transformedCorners = cv2.perspectiveTransform(corners,transform)
   rcTransformedCorners = transformedCorners.reshape(boardHeight,boardWidth,2)
   outerPoints = getOuterPoints(rcTransformedCorners)
   tl,tr,bl,br = outerPoints
   transformedPatternSize = np.array([
      np.sqrt(((tr - tl)**2).sum(0)),
      np.sqrt(((bl - tl)**2).sum(0)),
   ])
   dpi = (transformedPatternSize / realSizeMM) * 25.4
   print 'dpi before aspect ratio correction',dpi
   
   # correct aspect ratio (stretch the dimension with the lowest resolution so we don't loose data needlessly)
   if dpi[1] > dpi[0]:
      fx = dpi[1]/dpi[0]
      fy = 1.0
      print 'final dots per inch',dpi[1]
   else:
      fx = 1.0
      fy = dpi[0]/dpi[1]
      print 'final dots per inch',dpi[0]
      
   final = cv2.resize(transformed,None,fx=fx,fy=fy)
   
   return final

   
if __name__ == '__main__':
   realSizeMM = np.array([254.0,170.0])
   original = cv2.imread(r'calibration.jpg')

   i = correctPerspective(original.copy())
   cv2.imwrite('corrected-perspective-only.jpg',i)
   
   i = correctDistortion(original.copy())
   cv2.imwrite('corrected-distortion-only.jpg',i)
   i = correctPerspective(i)
   cv2.imwrite('corrected-both.jpg',i)
   print 'done'


And this is what happens when you run it on a calibration image:
autocalibrate.jpg
Automatic camera calibraion


It bothers me having to do corner detection twice -- once on the original image and once on the camera-corrected image. I need to read up on initUndistortRectifyMap in OpenCV so I can figure out how to apply the x/y map it generates as a transform to the corner coordinates so I can pass them straight in to the perspective correction step.
Attachments
chessboard.pdf
PDF of the chessboard pattern used for the code above
(8.7 KiB) Downloaded 81 times
og200
 
Posts: 62
Joined: 26 Mar 2012, 15:38
Location: Oxford, United Kingdom

Re: Automatic camera and DPI calibration

Postby og200 » 13 Apr 2012, 10:06

And just for fun here's what happens when you pass an absurdly poor shot through it. It's done on a 10mm lens on my Nikon D80 to make it as nasty as possible which is why it's rather out of focus at the bottom (I had to get very close).

distortion.jpg
distortion.jpg (75.63 KiB) Viewed 1583 times
og200
 
Posts: 62
Joined: 26 Mar 2012, 15:38
Location: Oxford, United Kingdom

Re: Automatic camera and DPI calibration

Postby tkr » 13 Apr 2012, 15:34

OG,
Very nice indeed - now that I have python set up on my machine (for ScanManager), how do I run the code that you have posted here ? Should I just wait for you to integrate it into Scanmanager ?

TKR
tkr
 
Posts: 30
Joined: 29 Jan 2012, 21:53

Re: Automatic camera and DPI calibration

Postby og200 » 13 Apr 2012, 16:21

I've integrated this into scanmanager so it will be in the next build. I have it working now I'll just do a bit of testing and I should be able to release a build soon if OpenCV and NumPy play nicely my packinging system.

For now here's a screenshot of it in action:
screenshot.jpg
ScanManager's automatic calibration/correction for dpi, keystone and some lens distortion
screenshot.jpg (128.41 KiB) Viewed 1553 times
og200
 
Posts: 62
Joined: 26 Mar 2012, 15:38
Location: Oxford, United Kingdom

Re: Automatic camera and DPI calibration

Postby daniel_reetz » 15 Apr 2012, 14:42

wow! great demo of camera calibration!
User avatar
daniel_reetz
 
Posts: 2482
Joined: 03 Jun 2009, 13:56

Re: Automatic camera and DPI calibration

Postby daniel_reetz » 15 Apr 2012, 14:44

og200 wrote:I've integrated this into scanmanager so it will be in the next build. I have it working now I'll just do a bit of testing and I should be able to release a build soon if OpenCV and NumPy play nicely my packinging system.
screenshot.jpg



I've had good luck getting both packages installed using SimpleCV- not sure if that will help or complicate your situation.
User avatar
daniel_reetz
 
Posts: 2482
Joined: 03 Jun 2009, 13:56

Re: Automatic camera and DPI calibration

Postby Anonymous2 » 15 Apr 2012, 15:00

SimpleCV is definitely the way to go. It's much easier to work with than OpenCV (no type conversions) and the unified installer works very well.
Anonymous2
 
Posts: 97
Joined: 18 Oct 2011, 16:05

Re: Automatic camera and DPI calibration

Postby og200 » 15 Apr 2012, 18:25

Wow, SimpleCV looks very slick! I'll definitely give it a try. (I needed to get at the underlying corner arrays and matricies to combine the perspective warp and undistort neatly but the SimpleCV API looks like a great starting point for a bunch of other things.)

As for building the package, it turns out py2exe handles OpenCV and numpy out of the box so the Windows .exe built with no issues. It's up here http://code.google.com/p/scan-manager/downloads/list now.

I also note, humbly, that this stuff has all been done here before in connection with the laser-based dewarping stuff -- I only came across that recently. It's a shame that effort seems to have died.
og200
 
Posts: 62
Joined: 26 Mar 2012, 15:38
Location: Oxford, United Kingdom

Re: Automatic camera and DPI calibration

Postby daniel_reetz » 15 Apr 2012, 20:55

It only "died" because few people had the hardware and there was little interest beyond that. Your app is slick enough that if we wanted to re-integrate it, it might have greater purchase this time. There is a fair amount of duplication/reworking around here and that is actually just fine - the different angles help us understand each problem in its fullness.

In my mind, the idea is to solidify our current knowledge in one form (the hackerspace scanner) and then move on to more "out there" technologies like laser lines, auto-calibrating cameras, and Kinect-based stuff. You're already working on it, which is GREAT, because I'm knee-deep in working on, frankly, old stuff and it's fun to watch someone take on more interesting work.
User avatar
daniel_reetz
 
Posts: 2482
Joined: 03 Jun 2009, 13:56

Re: Automatic camera and DPI calibration

Postby og200 » 16 Apr 2012, 09:12

It goes without saying that your work on the 'old' stuff is massively appreciated. I'm eagerly awaiting my own hackerspace scanner kit!

If I have time I'd like to have a go at the laser dewarping problem again. It looks like there was some working code and the tethered shooting stuff I'm playing with would seem like a sensible place to put this sort of thing.
og200
 
Posts: 62
Joined: 26 Mar 2012, 15:38
Location: Oxford, United Kingdom

Next

Return to Programs, Software releases, and more.

Who is online

Users browsing this forum: No registered users and 1 guest