Using CLsqFit with Image Pixels


Often, the data you need to fit come from an image. The example below describes how to efficiently fit the image values for a displayed image set. The key feature of this particular example is the CImage:Get method which fetches the pixel value from an image. This value is then added directly to the least squares sample using CLsqFit:AddPt.

This example assumes the image has a numeric data type (real, integer, etc.) with 1 channel. If the image is of the multi-channel (e.g., RGB) data type, use Gets instead of Get. The Gets method returns all channel values as a comma-separated string, a format that also is accepted by the AddPt method. Also note that the script uses CRect:Round to convert the fractional pixel locations of the cursor rectangle into exact integer values which correspond to the value at the center of each pixel.

Example

The following script fits a 2x2 polynomial "warped plane" to pixels inside the cursor rectangle on the images of a displayed image set. Since it works with a displayed image, you would place the target image window on top and run the script using [!] on the main menu (not the script editor window). The script first creates a CLsqFit object and sets the fit parameters. The script next attaches the top-most window, checks that it is an image window, and then loads the coordinates of its image cursor. Images are processed inside a loop that fits each member of the image set independently. The point sample is reset and then each point inside the image cursor rectangle is added to the CLsqFit point sample. After that, the fit is computed. If successful, you would insert code that does something with the fit—for example, you might store results in a table for later use or evaluate the fit and replace pixels having high residuals.

L = CLsqFit:new()

-- create the least squares fitting object

L:SetNumCoefs( {2,2} )

-- fit a 2,2 polynomial ("warped plane")

L:DoRejection()

-- enable data rejection with standard parameters

L:SetRejSigmaLow("10,4,3")

-- open up the lower sigma because outliers are positive

 

 

-- open and display images until the user clicks Cancel in the Open dialog

V = CImageView:Attach()

-- attach the top-most window that is an image window

Assert( V and V:Count() > 0, "no images were opened")

 

R = V:GetCursorRect()

-- Create a CRect for the cursor rectangle

if R:Width() * R:Height() > 1000 then

-- check the size. don't want too many points

  Exit("Too many points. Reduce the rectangle to include no more than 1000 points\n" )

end

 

R:Round()

-- round to exact integers for the pixel coords

 

 

for i = 1, V:Count() do

-- loop over each image

  I = V:GetImage(i)

-- create a CImage for the i-th displayed image

 

 

  L:ResetPoints()

-- clear out points from the prior image

 

 

  -- create a sample of points for fitting

  for j = R.ymin, R.ymax do

 

    for i = R.xmin, R.xmax do

 

      L:AddPt( { i, j }, I:Get(i,j) )

-- combine (x,y) coords in in a table ()

    end

 

  end

-- end of pixel adding loop

 

 

  bSuccess = L:Fit()

-- do the fit and check for success

  if bSuccess then

    -- do something with fit results

  end

 

end

-- end of image loop

Related Topics

CLsqFit class

Using the CLsqFit Class