using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HalconDotNet;
namespace HalconTools
{
public delegate void CalibDelegate(int value);
public class CalibrationAssistant
{
///
/// Constant indicating the camera model to be of type
/// line scan camera.
///
public const int CAMERA_TYP_LINE_SCAN = 3;
///
/// Constant indicating the camera model to be of type
/// area scan camera with the division
/// model to describe the lens distortions
///
public const int CAMERA_TYP_AREA_SCAN_DIV = 4;
///
/// Constant indicating the camera model to be of type
/// area scan camera with the polynomial
/// model to describe the lens distortions
///
public const int CAMERA_TYP_AREA_SCAN_POLY = 5;
///
/// Constant indicating a change in the set of
/// CalibImage instances regarding the parameters
/// marks and poses.
///
public const int UPDATE_MARKS_POSE = 10;
///
/// Constant indicating a change in the set of
/// CalibImage instances regarding the
/// quality assessment.
///
public const int UPDATE_QUALITY_TABLE = 12;
///
/// Constant indicating a change in the evaluation grades
/// of the CalibImage set. The grades measure the results
/// of the calibration preparations prior to the calibration
/// process itself.
///
public const int UPDATE_CALTAB_STATUS = 13;
///
/// Constant indicating an update of the calibration
/// results.
///
public const int UPDATE_CALIBRATION_RESULTS = 14;
///
/// Constant indicating that the quality measurement
/// includes all quality assessment operators for
/// evaluating the set of calibration images.
///
public const int QUALITY_ISSUE_TEST_ALL = 0;
///
/// Constant indicating that the quality measurement uses only the
/// basic quality assessment operators for speedup purposes.
///
public const int QUALITY_ISSUE_TEST_QUICK = 1;
///
/// Constant indicating no quality measurement
/// for the set of calibration images.
///
public const int QUALITY_ISSUE_TEST_NONE = 2;
///
/// Constant indicating the image quality feature 'exposure'
///
public const int QUALITY_ISSUE_IMG_EXPOSURE = 20;
///
/// Constant indicating the image quality feature 'homogeneity'
///
public const int QUALITY_ISSUE_IMG_HOMOGENEITY = 21;
///
/// Constant indicating the image quality feature 'contrast'
///
public const int QUALITY_ISSUE_IMG_CONTRAST = 22;
///
/// Constant indicating the image quality feature 'sharpness'
///
public const int QUALITY_ISSUE_IMG_FOCUS = 23;
///
/// Constant indicating the size of the depicted
/// calibration plate in the calibration image, to evaluate
/// the distance used to the camera
///
public const int QUALITY_ISSUE_IMG_CALTAB_SIZE = 24;
///
/// Constant indicating the coverage of the view field.
/// This is assured only by a sufficient number of
/// calibration images and its correct distribution in the space.
///
public const int QUALITY_ISSUE_SEQ_MARKS_DISTR = 25;
///
/// Constant indicating the amount of distortions covered,
/// described by the set of images showing tilted calibration
/// plates
///
public const int QUALITY_ISSUE_SEQ_CALTAB_TILT = 26;
///
/// Constant indicating whether the number of provided calibration
/// images is sufficient enough to obtain stable calibration results.
///
public const int QUALITY_ISSUE_SEQ_NUMBER = 27;
///
/// Constant indicating the all over quality performance,
/// being best for a value close or equal to 1
///
public const int QUALITY_ISSUE_SEQ_ALL_OVER = 28;
///
/// Constant that indicates an error in the calibration
/// preprocessing step, which has to perform well for the
/// whole sequence of calibration images in order to start
/// the calibration process.
///
public const int QUALITY_ISSUE_SEQ_ERROR = 29;
///
/// Constant indicating an error in the preprocessing step
/// for a single calibration image, i.e., that the
/// marks and pose values might be missing or the region
/// plate couldn't be detected
///
public const int QUALITY_ISSUE_FAILURE = 30;
///
/// Constant describing an error while reading a
/// calibration image from file
///
public const int ERR_READING_FILE = 31;
///
/// Constant describing an error exception raised during
/// the calibration process
///
public const int ERR_IN_CALIBRATION = 32;
///
/// Constant indicating an invalid reference index. The
/// index is needed to define the reference image for
/// the camera calibration.
///
public const int ERR_REFINDEX_INVALID = 33;
///
/// Constant describing an error exception raised
/// during quality assessment.
///
public const int ERR_QUALITY_ISSUES = 34;
///
/// Constant describing an error that occurred while
/// writing the calibration parameters into file
///
public const int ERR_WRITE_CALIB_RESULTS = 35;
///
/// Constant indicating the result status of the
/// calibration preparation step:
/// Plate region couldn't be detected in the
/// calibration image.
///
public const string PS_NOT_FOUND = "Plate not found";
///
/// Constant that describes the results of the
/// calibration preparation step:
/// Plate region was detected, but the marks could not
/// be extracted in the plate region.
///
public const string PS_MARKS_FAILED = "Marks not found";
///
/// Constant indicating the result status of the
/// calibration preparation step:
/// Plate region and marks were detected,
/// but the quality assessment delivered bad scores.
///
public const string PS_QUALITY_ISSUES = "Quality issues detected";
///
/// Constant indicating the result status of the
/// calibration preparation step:
/// The preprocessing step was successful.
///
public const string PS_OK = "Ok";
///
/// List of calibration images that are used
/// to perform the camera calibration.
///
private ArrayList CalibData;
///
/// Index to the reference image that is used to
/// determine the initial values for the internal camera
/// parameters for the camera calibration
///
public int mReferenceIndex;
private QualityProcedures procedure;
// CALIBRATION RESULTS -----------------------------------------
///
/// Flag indicating that the calibration was successful and
/// the present calibration results are up to date
///
public bool mCalibValid;
///
/// The average error give an impression of the accuracy of the
/// calibration. The error (deviations in x and y coordinates) are
/// measured in pixels
///
public double mErrorMean;
///
/// Ordered tuple with the external camera parameters for all
/// calibration images, i.e., the position and orientation of the
/// calibration plate in camera coordinates.
///
public HTuple mPoses;
///
/// Internal camera parameters
///
public HTuple mCameraParams;
///
/// Error contents that caused an exception
///
public string mErrorMessage;
///
/// Calibration image at index mReferenceIndex
///
public HImage mReferenceImage;
///
/// Synthetic calibration images with calibrated camera
/// parameters to test the quality of the calibration
/// algorithm
///
public HImage mSimulatedImage;
///
/// Reference world coordinate system, based on
/// mPose and the calibrated camera parameters
///
public HObject mReferenceWCS;
///
/// Flag describing whether all calibration images
/// have a sufficient quality, i.e. whether the region plate and
/// marks have been detected in all calibration images,
/// so that a camera calibration can be invoked
///
public bool mCanCalib;
///
/// Flag indicating that the origin of the reference world coordinate
/// system mReferenceWCS is mapped to the origin of the image
/// coordinate system.
///
public bool mAtImgCoord;
// FIRST TAB -----------------------------------------------
///
/// Name of the calibration plate description file to read
/// the mark center points from
///
public string mDescrFileName;
///
/// Thickness of the calibration plate that was used in the
/// calibration images
///
public double mThickness;
///
/// Camera type, which can either be an area scan camera
/// (using the division or polynomial model) or a linescan camera
///
public int mCameraType;
///
/// Horizontal distance between two neighboring CCD
/// sensor cells
///
public double mCellWidth; // Sx
///
/// Vertical distance between two neighboring CCD
/// sensor cells
///
public double mCellHeight; // Sy
///
/// Nominal focal length of the camera lense
///
public double mFocalLength;
///
/// Parameter to model the radial distortion described by
/// the division model
///
public double mKappa;
///
/// First parameter to model the radial distortion described by
/// the polynomial model
///
public double mK1;
///
/// Second parameter to model the radial distortion described by
/// the polynomial model
///
public double mK2;
///
/// Third parameter to model the radial distortion described by
/// the polynomial model
///
public double mK3;
///
/// First parameter to model the decentering distortion described by
/// the polynomial model
///
public double mP1;
///
/// Second parameter to model the decentering distortion described by
/// the polynomial model
///
public double mP2;
///
/// Flag indicating the type of camera lense used:
/// telecentric, which means a parallel projection with the focal
/// length equal to 0, or a perspective projection
///
public bool isTelecentric;
///
/// X component of the motion vector, which describes the motion
/// between the linescan camera and the object.
///
public double mMotionVx;
///
/// Y component of the motion vector, which describes the motion
/// between the linescan camera and the object.
///
public double mMotionVy;
///
/// Z component of the motion vector, which describes the motion
/// between the linescan camera and the object.
///
public double mMotionVz;
// SECOND TAB ---------------------------------------------
private int mWarnLevel;
private int mImageTests;
private int mSequenceTests;
///
/// List of quality assessment scores of the whole set of calibration
/// images.
///
public ArrayList mSeqQualityList;
///
/// Size of the filter mask that is used to smooth the
/// image before determining the region plate in the
/// calibration image
///
public double mFilterSize;
///
/// Threshold value for mark extraction
///
public double mMarkThresh;
///
/// Expected minimum diameter of the marks on the
/// calibration plate
///
public double mMinMarkDiam;
///
/// Initial threshold value for contour detection
///
public double mInitThresh;
///
/// Loop value for successive reduction of
/// the initial threshold mInitThresh
///
public double mThreshDecr;
///
/// Minimum threshold for contour detection
///
public double mMinThresh;
///
/// Filter parameter for contour detection
///
public double mSmoothing;
///
/// Minimum length of the contours of the marks
///
public double mMinContLength;
///
/// Maximum expected diameter of the marks
///
public double mMaxMarkDiam;
// reset vals
public int resetFilterSize = 9;
public int resetMarkThresh = 180;
public int resetMinMarkDiam = 5;
public int resetInitThresh = 128;
public int resetThreshDecr = 10;
public int resetMinThresh = 18;
public double resetSmoothing = 0.9; /* 90*0.01 */
public int resetMinContL = 15;
public int resetMaxMarkDiam = 500;
///
/// Delegate to notify the GUI about changes in the data models
///
public CalibDelegate NotifyCalibObserver;
/* Constructor, in which all calibration parameters
* and auxiliary variables, flags and lists are initilized */
public CalibrationAssistant()
{
CalibData = new ArrayList(15);
mReferenceIndex = -1;
mDescrFileName = "caltab_10mm.descr";
mCalibValid = false;
mCanCalib = true;
mAtImgCoord = false;
mReferenceImage = new HImage();
mSimulatedImage = new HImage();
mFilterSize = resetFilterSize;
mMarkThresh = resetMarkThresh;
mMinMarkDiam = resetMinMarkDiam;
mInitThresh = resetInitThresh;
mThreshDecr = resetThreshDecr;
mMinThresh = resetMinThresh;
mSmoothing = resetSmoothing;
mMinContLength = resetMinContL;
mMaxMarkDiam = resetMaxMarkDiam;
mWarnLevel = 70;
mImageTests = QUALITY_ISSUE_TEST_ALL;
mSequenceTests = QUALITY_ISSUE_TEST_ALL;
mSeqQualityList = new ArrayList(15);
procedure = new QualityProcedures();
mThickness = 1.00; // millimeter
mCameraType = CAMERA_TYP_AREA_SCAN_DIV;
mCellWidth = 8.300; // micrometer
mCellHeight = 8.300; // micrometer
mFocalLength = 8.000; // millimeter
isTelecentric = false;
mKappa = 0.0;
mK1 = 0.0;
mK2 = 0.0;
mK3 = 0.0;
mP1 = 0.0;
mP2 = 0.0;
mMotionVx = 0.0;
mMotionVy = 500.0;
mMotionVz = 0.0;
NotifyCalibObserver = new CalibDelegate(dummy);
}
/*******************************************/
/********** Tab.1 ************/
/*******************************************/
///
/// Sets the reference index to the supplied value
///
public void setReferenceIdx(int val)
{
mReferenceIndex = val;
}
/*******************************************/
///
/// Sets the file path for the description file to
/// the supplied value
///
///
/// Absolute path to the description file
///
public void setDesrcFile(string fileName)
{
mDescrFileName = fileName;
Update();
}
///
/// Gets the path to the description file used
/// with the calibration
///
public string getDesrcFile()
{
return mDescrFileName;
}
/*******************************************/
///
/// Sets the thickness parameter to the supplied value
///
public void setThickness(double val)
{
mThickness = val;
UpdateResultVisualization();
}
///
/// Returns the current value for the thickness of the calibration
/// plate.
///
public double getThickness()
{
return mThickness;
}
/*******************************************/
///
/// Sets the camera type to the supplied value and
/// invokes an update to adjust data for the calibration images.
///
///
public void setCameraType(int mode)
{
mCameraType = mode;
Update(true);
}
///
/// Returns the current camera type.
///
public int getCameraType()
{
return mCameraType;
}
/*******************************************/
///
/// Sets the parameter for the CCD sensor cell width
/// to the supplied value.
///
public void setCellWidth(double val)
{
mCellWidth = val;
Update();
}
///
/// Returns the value for the CCD sensor cell width
///
public double getCellWidth()
{
return mCellWidth;
}
/*******************************************/
///
/// Sets the parameter for the CCD sensor cell height
/// to the supplied value.
///
public void setCellHeight(double val)
{
mCellHeight = val;
Update();
}
///
/// Returns the value for the CCD sensor cell height
///
public double getCellHeight()
{
return mCellHeight;
}
/*******************************************/
///
/// Sets the parameter for the focal length to the
/// supplied value
///
public void setFocalLength(double val)
{
mFocalLength = val;
Update();
}
///
/// Returns the current value for the focal length
///
public double getFocalLength()
{
return mFocalLength;
}
/*******************************************/
///
/// Sets the boolean flag to indicate the use of telecentric
/// lense
///
public void setIsTelecentric(bool val)
{
isTelecentric = val;
Update();
}
///
/// Returns whether the current camera lense is defined to
/// be telecentric or not
///
public bool IsTelecentric()
{
return isTelecentric;
}
/*******************************************/
///
/// Sets the motion vector Vx to the supplied
/// value
///
public void setMotionX(double val)
{
mMotionVx = val;
Update();
}
///
/// Gets the current value for the motion vector Vx
///
public double getMotionX()
{
return mMotionVx;
}
/*******************************************/
///
/// Sets the motion vector Vy to the supplied
/// value
///
public void setMotionY(double val)
{
mMotionVy = val;
Update();
}
///
/// Gets the current value for the motion vector Vy
///
public double getMotionY()
{
return mMotionVy;
}
/*******************************************/
///
/// Sets the motion vector Vz to the supplied
/// value
///
public void setMotionZ(double val)
{
mMotionVz = val;
Update();
}
///
/// Gets the current value for the motion vector Vz
///
public double getMotionZ()
{
return mMotionVz;
}
/*******************************************/
/********** Tab.2 ************/
/*******************************************/
/*******************************************/
///
/// Sets the parameter for the warn level to
/// the supplied value.
///
public void setWarnLevel(int val)
{
mWarnLevel = val;
Update(true);
}
///
/// Gets the current value for the warn level
///
public double getWarnLevel()
{
return mWarnLevel;
}
/*******************************************/
///
/// Sets the parameter to define the mode (accuracy) of
/// the quality assessment for single
/// calibration images
///
///
/// mode (accuracy) of the quality assessment; one of the constants
/// starting with QUALITY_ISSUE_TEST_*.
///
public void setImageTests(int mode)
{
mImageTests = mode;
Update(true);
}
///
/// Gets the current value that describes the
/// accuracy of the quality assessment
///
public double getImageTests()
{
return mImageTests;
}
/*******************************************/
///
/// Sets the parameter to define the mode (accuracy) of
/// the quality assessment for the whole sequence
/// of calibration images
///
///
/// mode (accuracy) of the quality assessment; one of the constants
/// starting with QUALITY_ISSUE_TEST_*.
///
public void setSequenceTests(int mode)
{
mSequenceTests = mode;
Update(true);
}
///
/// Gets the current value that describes the
/// accuracy of the quality assessment
///
public double getSequenceTests()
{
return mSequenceTests;
}
/*******************************************/
///
/// Sets the parameter for the filter size to
/// the supplied value.
///
public void setFilterSize(double val)
{
mFilterSize = val;
Update();
}
///
/// Gets the current value for the parameter
/// describing the filter size
///
public double getFilterSize()
{
return mFilterSize;
}
/*******************************************/
///
/// Sets the parameter for mark threshold to
/// the supplied value.
///
public void setMarkThresh(double val)
{
mMarkThresh = val;
Update();
}
///
/// Gets the current value for the parameter
/// describing the mark threshold
///
public double getMarkThresh()
{
return mMarkThresh;
}
/*******************************************/
///
/// Sets the parameter for the minimum mark
/// diameter to the supplied value.
///
public void setMinMarkDiam(double val)
{
mMinMarkDiam = val;
Update();
}
///
/// Gets the current value for the parameter
/// describing the minimum mark diameter
///
public double getMinMarkDiam()
{
return mMinMarkDiam;
}
/*******************************************/
///
/// Sets the parameter for the start threshold
/// to the supplied value.
///
public void setInitThresh(double val)
{
mInitThresh = val;
Update();
}
///
/// Gets the current value for the parameter
/// describing the start threshold
///
public double getInitThresh()
{
return mInitThresh;
}
/*******************************************/
///
/// Sets the parameter for the threshold
/// decrement to the supplied value.
///
public void setThreshDecr(double val)
{
mThreshDecr = val;
Update();
}
///
/// Gets the current value for the parameter
/// describing the threshold decrement
///
public double getThreshDecr()
{
return mThreshDecr;
}
/*******************************************/
///
/// Sets the parameter for the minimum
/// threshold to the supplied value.
///
public void setMinThresh(double val)
{
mMinThresh = val;
Update();
}
///
/// Gets the current value for the parameter
/// describing the minimum threshold
///
public double getMinThresh()
{
return mMinThresh;
}
/*******************************************/
///
/// Sets the parameter describing the smoothing
/// factor to the supplied value.
///
public void setSmoothing(double val)
{
mSmoothing = val;
Update();
}
///
/// Gets the parameter describing the smoothing
/// factor
///
public double getSmoothing()
{
return mSmoothing;
}
/*******************************************/
///
/// Sets the parameter describing the minimum
/// contour length to the supplied value.
///
public void setMinContLength(double val)
{
mMinContLength = val;
Update();
}
///
/// Gets the parameter describing the minimum
/// contour length
///
public double getMinContLength()
{
return mMinContLength;
}
/*******************************************/
///
/// Sets the parameter describing the maximum
/// mark diameter to the supplied value.
///
public void setMaxMarkDiam(double val)
{
mMaxMarkDiam = val;
Update();
}
///
/// Gets the parameter describing the maximum
/// mark diameter
///
public double getMaxMarkDiam()
{
return mMaxMarkDiam;
}
/*******************************************/
///
/// Sets the flag defining the origin of
/// the reference world coordinate system
/// to be in the image coordinate system
///
public void setAtImgCoord(bool val)
{
mAtImgCoord = val;
UpdateResultVisualization();
}
///
/// Gets the current value for the flag
///
public bool getAtImgCoord()
{
return mAtImgCoord;
}
public void dummy(int val) { }
/*******************************************/
/*******************************************/
/*******************************************/
/*******************************************/
///
/// Gets the calibration image for the index i
/// from the list CalibData
///
public CalibImage getCalibDataAt(int i)
{
if (CalibData.Count > 0)
return (CalibImage)CalibData[i];
else
return null;
}
public int getCalibDataLength()
{
return CalibData.Count;
}
///
/// Add a new calibration image to the list CalibData.
/// The image is read from the location filename
/// and a new calibration image instance is then
/// generated, embedding this image.
/// As a preparation step prior to the calibration process, the
/// basic information for the calibration image are determined,
/// in terms of: detection of the region plate and the marks
/// and pose.
///
///
/// Instance of a calibration image model created for
/// the calibration image, supplied by filename
///
public CalibImage addImage(string filename)
{
HImage image = null;
CalibImage data = null;
try
{
image = new HImage(filename);
data = new CalibImage(image, this);
CalibData.Add(data);
data.UpdateCaltab(true);
mCanCalib = (mCanCalib && (data.mCanCalib == 0));
mCalibValid = false;
}
catch (HOperatorException e)
{
mErrorMessage = e.Message;
NotifyCalibObserver(CalibrationAssistant.ERR_READING_FILE);
}
return data;
}
///
/// Removes the instance of the calibration images
/// at the index index from the list CalibData
///
public void removeImage(int index)
{
((CalibImage)CalibData[index]).Clear();
CalibData.RemoveAt(index);
mCalibValid = false;
getCanCalibrate();
NotifyCalibObserver(CalibrationAssistant.UPDATE_CALIBRATION_RESULTS);
}
///
/// Removes all instances of the calibration images
/// from the list CalibData
///
public void removeImage()
{
int count = CalibData.Count;
for (int i = 0; i < count; i++)
((CalibImage)CalibData[i]).Clear();
CalibData.Clear();
mCalibValid = false;
mCanCalib = false;
NotifyCalibObserver(CalibrationAssistant.UPDATE_CALIBRATION_RESULTS);
}
///
/// Gets the HALCON image with the index index in the list of
/// calibration images CalibData.
///
public HImage getImageAt(int index)
{
if (CalibData.Count > 0)
return ((CalibImage)CalibData[index]).getImage();
return null;
}
///
/// Resets the flag mCanCalib to the boolean 'true'
///
public void resetCanCalib()
{
mCanCalib = true;
}
///
/// Returns the reference image for the calibration process
///
public HImage getRefImage()
{
return (HImage)mReferenceImage;
}
///
/// Returns the simulated image obtained from
/// the calibration process
///
public HImage getSimulatedImage()
{
return mSimulatedImage;
}
///
/// Returns the reference world coordinate system
/// obtained from the calibration process
///
///
public HObject getReferenceWCS()
{
return mReferenceWCS;
}
/*******************************************/
///
/// Auxiliary method prior to the actual update
/// routine. Calls the actual update method
/// omitting the quality assessment for the
/// set of calibration image models.
///
public void Update()
{
bool doQuality = false;
Update(doQuality);
}
///
/// Updates the data of the calibration images
/// if a change occurred in the calibration parameters.
/// The quality assessment is performed if the
/// supplied value is positive; otherwise, it is omited.
///
///
/// If the flag is positive, an update of the
/// quality assessment is invoked, otherwise not.
///
public void Update(bool doQuality)
{
int count;
if ((count = CalibData.Count) == 0)
return;
try
{
for (int i = 0; i < count; i++)
((CalibImage)CalibData[i]).UpdateCaltab(doQuality);
if (doQuality)
UpdateSequenceIssues();
mCanCalib = getCanCalibrate();
NotifyCalibObserver(CalibrationAssistant.UPDATE_CALTAB_STATUS);
NotifyCalibObserver(CalibrationAssistant.UPDATE_MARKS_POSE);
if (doQuality)
NotifyCalibObserver(CalibrationAssistant.UPDATE_QUALITY_TABLE);
}
catch (HOperatorException e)
{
mErrorMessage = (string)e.Message;
mCanCalib = false;
NotifyCalibObserver(CalibrationAssistant.ERR_QUALITY_ISSUES);
}
if (mCalibValid)
{
mCalibValid = false;
NotifyCalibObserver(CalibrationAssistant.UPDATE_CALIBRATION_RESULTS);
}
}
/*******************************************/
///
/// Checks the whole set of calibration image models for
/// the quality of the preprocessing step. If the basic
/// information, i.e. the region plate and the marks
/// and pose, was extracted in all images, then the
/// flag mCanCalib is positive, which means
/// the actual calibration process can be initiated
///
///
/// Flag indicating the feasibility of the calibration
/// process
///
public bool getCanCalibrate()
{
int count = CalibData.Count;
int val = 0;
for (int i = 0; i < count; i++)
val += ((CalibImage)CalibData[i]).mCanCalib;
if (val == 0 && count > 0)
mCanCalib = true;
else
mCanCalib = false;
return mCanCalib;
}
///
/// Gets the mark centers and the poses extracted from
/// the set of calibration images
///
///
/// Tuple of row coordinates of all marks from
/// the entire set of calibration images
///
///
/// Tuple of column coordinates of all marks from
/// the entire set of calibration images
///
///
/// Tuple of estimated poses for the entire set
/// of calibration images
///
public HTuple getCalibrationData(out HTuple rows, out HTuple cols)
{
int count = CalibData.Count;
HTuple pose = new HTuple();
rows = new HTuple();
cols = new HTuple();
CalibImage image;
for (int i = 0; i < count; i++)
{
image = (CalibImage)CalibData[i];
pose = pose.TupleConcat(image.getEstimatedPose());
rows = rows.TupleConcat(image.getMarkCenterRows());
cols = cols.TupleConcat(image.getMarkCenterColumns());
}
return pose;
}
///
/// Gets the camera parameters corresponding to
/// the supplied calibration image.
///
/// Camera parameters
public HTuple getCameraParams(CalibImage image)
{
HTuple campar;
int paramsListSize = 8;
int offset = 0;
bool areaScanPoly = false;
if (mCameraType == CalibrationAssistant.CAMERA_TYP_AREA_SCAN_POLY)
{
paramsListSize = 12;
offset = 4;
areaScanPoly = true;
}
paramsListSize += (mCameraType == CalibrationAssistant.CAMERA_TYP_LINE_SCAN) ? 3 : 0;
campar = new HTuple(paramsListSize);
campar[0] = (isTelecentric ? 0.0 : ((double)mFocalLength / 1000.0));
if (areaScanPoly)
{
campar[1] = mK1;
campar[2] = mK2;
campar[3] = mK3;
campar[4] = mP1;
campar[5] = mP2;
}
else
{
campar[1] = mKappa;
}
campar[2 + offset] = (double)mCellWidth / 1000000.0; // Sx -width -> * 10^ -6
campar[3 + offset] = (double)mCellHeight / 1000000.0; // Sy -height -> * 10^ -6
campar[4 + offset] = (double)image.mWidth * 0.5; // x -principal point
campar[5 + offset] = (double)image.mHeight * 0.5; // y -principal point
campar[6 + offset] = image.mWidth; // imagewidth
campar[7 + offset] = image.mHeight; // imageheight
if (paramsListSize == 11)
{
campar[8] = mMotionVx / 1000000.0;
campar[9] = mMotionVy / 1000000.0;
campar[10] = mMotionVz / 1000000.0;
campar[5 + offset] = 0; // y -principal point = 0 for line scan camera
}
return campar;
}
///
/// Tests different quality features for the calibration image
/// cImg
///
///
/// Returns a value indicating the success or failure
/// of the quality assessment
///
public bool testQualityIssues(CalibImage cImg)
{
ArrayList qList;
HObject markContours;
HObject plateRegion;
HImage mImg;
HTuple score, score2, contrast;
int numRegions, numContours;
bool qualityFailure;
mImg = cImg.getImage();
qList = cImg.getQualityIssueList();
procedure = new QualityProcedures();
contrast = new HTuple();
qualityFailure = false;
// DescriptionFileName = mDescrFileName;
;
try
{
procedure.find_caltab_edges(mImg, out plateRegion,
out markContours,
new HTuple(mDescrFileName));
numRegions = plateRegion.CountObj();
numContours = markContours.CountObj();
if (mImageTests < QUALITY_ISSUE_TEST_NONE)
{
if (numRegions == 0)
{
qualityFailure = true;
}
else
{
procedure.eval_caltab_overexposure(mImg, plateRegion, out score);
addQualityIssue(qList, QUALITY_ISSUE_IMG_EXPOSURE, score.D);
}
if (numContours == 0)
{
qualityFailure = true;
}
else
{
procedure.eval_caltab_contrast_homogeneity(mImg, markContours, out contrast, out score, out score2);
addQualityIssue(qList, QUALITY_ISSUE_IMG_CONTRAST, score.D);
addQualityIssue(qList, QUALITY_ISSUE_IMG_HOMOGENEITY, score2.D);
procedure.eval_caltab_size(mImg, plateRegion, markContours, out score);
addQualityIssue(qList, QUALITY_ISSUE_IMG_CALTAB_SIZE, score.D);
}
if (mImageTests == QUALITY_ISSUE_TEST_ALL)
{
procedure.eval_caltab_focus(mImg, markContours, contrast, out score);
addQualityIssue(qList, QUALITY_ISSUE_IMG_FOCUS, score.D);
}
}
}
catch (HOperatorException e)
{
throw (e);
}
return qualityFailure;
}
///
/// Tests for quality features concerning the performance
/// of the entire sequence of calibration images provided by
/// the list CalibData
///
public void UpdateSequenceIssues()
{
HTuple markRows, marksCols, startPose, width, height, hScore;
bool hasIssue;
bool hasError;
double minScore, score;
int count, countL;
CalibImage imgC;
ArrayList qList;
mSeqQualityList.Clear();
try
{
if (mSequenceTests < QUALITY_ISSUE_TEST_NONE)
{
hasIssue = false;
hasError = false;
minScore = 1.0;
if ((count = CalibData.Count) == 0)
return;
for (int i = 0; i < count; i++)
{
imgC = (CalibImage)CalibData[i];
if (imgC.getPlateStatus() == PS_QUALITY_ISSUES)
{
hasIssue = true;
qList = imgC.getQualityIssueList();
countL = qList.Count;
for (int j = 0; j < countL; j++)
{
score = ((QualityIssue)qList[j]).getScore();
if (score < minScore)
minScore = score;
}
}
else if (imgC.getPlateStatus() != PS_OK)
{
hasError = true;
}
}//for
if (hasError)
{
addQualityIssue(mSeqQualityList, QUALITY_ISSUE_SEQ_ERROR, 0.0);
}
else if (hasIssue)
{
addQualityIssue(mSeqQualityList, QUALITY_ISSUE_SEQ_ALL_OVER, minScore);
}
if (count < 20)
{
score = (count <= 10) ? 0.0 : (0.1 * ((double)count - 10.0));
addQualityIssue(mSeqQualityList, QUALITY_ISSUE_SEQ_NUMBER, score);
}
if (mSequenceTests == QUALITY_ISSUE_TEST_ALL && count > 0)
{
startPose = getCalibrationData(out markRows, out marksCols);
width = new HTuple(((CalibImage)CalibData[0]).mWidth);
height = new HTuple(((CalibImage)CalibData[0]).mHeight);
procedure.eval_marks_distribution(markRows, marksCols, width, height, out hScore);
addQualityIssue(mSeqQualityList, QUALITY_ISSUE_SEQ_MARKS_DISTR, hScore[0].D);
procedure.eval_caltab_tilt(startPose, out hScore);
addQualityIssue(mSeqQualityList, QUALITY_ISSUE_SEQ_CALTAB_TILT, hScore[0].D);
}
}//if!=None
}
catch (HOperatorException e)
{
mErrorMessage = e.Message;
}
}
///
/// Adds the calculated score score for the quality feature
/// type to the supplied feature list qList
///
///
/// Quality feature list
///
///
/// Constant starting with QUALITY_*, describing one of the quality
/// features
///
///
/// Score determined for the quality feature
///
public void addQualityIssue(ArrayList qList, int type, double score)
{
if ((int)(score * 100) <= mWarnLevel)
qList.Add(new QualityIssue(type, score));
}
///
/// Calls the actual addQualityIssue
/// method, with the feature list obtained from the
/// calibration image cImg
///
///
/// Calibration image model, which has been tested for
/// the quality feature defined with type
///
///
/// Constant starting with QUALITY_* describing one of the quality
/// features
///
///
/// Score determined for the quality feature
///
public void addQualityIssue(CalibImage cImg, int type, double score)
{
ArrayList qList = cImg.getQualityIssueList();
addQualityIssue(qList, type, score);
}
///
/// Applies the calibration on the set of calibration
/// images CalibData
///
public void applyCalibration()
{
HTuple x, y, z, marksR, marksC;
HTuple error, startPoses, startCampar, parameters;
CalibImage refImg;
mCalibValid = false;
mErrorMean = -1;
if (mReferenceIndex >= 0)
{
try
{
refImg = (CalibImage)CalibData[mReferenceIndex];
HOperatorSet.CaltabPoints(mDescrFileName, out x, out y, out z);
startPoses = getCalibrationData(out marksR, out marksC);
startCampar = getCameraParams(refImg);
parameters = new HTuple("all");
HOperatorSet.CameraCalibration(x, y, z,
marksR, marksC,
startCampar,
startPoses,
parameters,
out mCameraParams,
out mPoses,
out error);
mErrorMean = error[0].D;
mCalibValid = true;
UpdateResultVisualization();
}
catch (HOperatorException e)
{
mErrorMessage = e.Message;
NotifyCalibObserver(CalibrationAssistant.ERR_IN_CALIBRATION);
}
}
else
{
NotifyCalibObserver(CalibrationAssistant.ERR_REFINDEX_INVALID);
}//if-else
}
///
/// Generates the iconic objects of the calibration results
/// for display
///
public void UpdateResultVisualization()
{
HTuple refPose, correctedPose;
double axisLen;
HObject obj;
if (!mCalibValid)
return;
mSimulatedImage.Dispose();
mReferenceImage = ((CalibImage)CalibData[mReferenceIndex]).getImage();
refPose = getCalibratedPose(false);
HOperatorSet.SimCaltab(out obj, new HTuple(mDescrFileName),
mCameraParams, refPose, new HTuple(128),
new HTuple(224), new HTuple(80), new HTuple(1));
mSimulatedImage = new HImage(obj);
correctedPose = getCalibratedPose(true);
axisLen = ((CalibImage)CalibData[mReferenceIndex]).getEstimatedPlateSize();
procedure.get_3d_coord_system(mReferenceImage, out mReferenceWCS, mCameraParams,
correctedPose, new HTuple(axisLen / 2));
NotifyCalibObserver(CalibrationAssistant.UPDATE_CALIBRATION_RESULTS);
}
///
/// Saves the calibrated camera parameters in the file
/// defined by filename
///
public void saveCamParams(string filename)
{
if (mCalibValid)
{
try
{
HOperatorSet.WriteCamPar(mCameraParams, new HTuple(filename));
}
catch (HOperatorException e)
{
mErrorMessage = e.Message;
NotifyCalibObserver(CalibrationAssistant.ERR_WRITE_CALIB_RESULTS);
}
}
}
///
/// Saves the pose obtained from the camera calibration
/// in the file, defined by filename
///
public void saveCamPose(string filename)
{
HTuple Pose;
if (mCalibValid)
{
try
{
Pose = getCalibratedPose(true);
HOperatorSet.WritePose(Pose, new HTuple(filename));
}
catch (HOperatorException e)
{
mErrorMessage = e.Message;
NotifyCalibObserver(CalibrationAssistant.ERR_WRITE_CALIB_RESULTS);
}
}
}
///
/// Returns calibration results
///
///
/// Calibrated internal camera parameters
///
///
/// Calibrated external camera parameters
///
public void getCalibrationResult(out HTuple camParams,
out HTuple refPose)
{
camParams = new HTuple(mCameraParams);
refPose = getCalibratedPose(true);
}
///
/// Returns the calibrated reference pose
///
public HTuple getCalibratedPose(bool corrected)
{
HTuple tX, tY, tZ, correctedPose, refPose = null;
if (!mCalibValid)
return new HTuple(1.0, -1.0, 0.0);
if (mPoses.Length >= 7 * (mReferenceIndex + 1))
refPose = mPoses.TupleSelectRange(new HTuple(7 * mReferenceIndex),
new HTuple(7 * mReferenceIndex + 6));
if (!corrected)
return refPose;
tX = new HTuple(0);
tY = new HTuple(0);
tZ = new HTuple(this.mThickness / 1000.0);
if (mAtImgCoord)
{
HOperatorSet.ImagePointsToWorldPlane(mCameraParams, refPose,
new HTuple(0), new HTuple(0),
new HTuple("mm"), out tX, out tY);
}
HOperatorSet.SetOriginPose(refPose, tX, tY, tZ, out correctedPose);
return correctedPose;
}
/// Loads camera parameters from file
/// File name
/// Success or failure of load process
public bool importCamParams(string camParFile)
{
HTuple campar;
int offset = 0;
bool areaScanPoly = false;
try
{
HOperatorSet.ReadCamPar(new HTuple(camParFile), out campar);
// -- load camera parameters --
switch (campar.Length)
{
case 8:
mCameraType = CAMERA_TYP_AREA_SCAN_DIV;
break;
case 11:
mCameraType = CAMERA_TYP_LINE_SCAN;
break;
case 12:
mCameraType = CAMERA_TYP_AREA_SCAN_POLY;
offset = 4;
areaScanPoly = true;
break;
default:
mCameraType = -1;
break;
}
mFocalLength = campar[0] * 1000.0;
if (mFocalLength == 0.0)
isTelecentric = true;
else
isTelecentric = false;
if (areaScanPoly)
{
mK1 = campar[1];
mK2 = campar[2];
mK3 = campar[3];
mP1 = campar[4];
mP2 = campar[5];
}
else
{
mKappa = campar[1];
}
mCellWidth = campar[2 + offset] * 1000000.0;
mCellHeight = campar[3 + offset] * 1000000.0;
// line scan camera
if (campar.Length == 11)
{
mMotionVx = campar[8].D * 1000000.0;
mMotionVy = campar[9].D * 1000000.0;
mMotionVz = campar[10].D * 1000000.0;
}
Update(true);
}
catch (HOperatorException e)
{
mErrorMessage = e.Message;
NotifyCalibObserver(CalibrationAssistant.ERR_READING_FILE);
return false;
}
return true;
}
///
/// Resets the camera parameters to the default settings.
///
///
/// Flag to change camera type to the default as well
///
public void resetCameraSetup(bool camTyp)
{
if (camTyp)
mCameraType = CAMERA_TYP_AREA_SCAN_DIV;
mThickness = 1.00;
mCellWidth = 8.300;
mCellHeight = 8.300;
mFocalLength = 8.000;
isTelecentric = false;
mKappa = 0.0;
mK1 = 0.0;
mK2 = 0.0;
mK3 = 0.0;
mP1 = 0.0;
mP2 = 0.0;
mMotionVx = 0.0;
mMotionVy = 500.0;
mMotionVz = 0.0;
Update(true);
}
}
}