Brian Silverman | 26e4e52 | 2015-12-17 01:56:40 -0500 | [diff] [blame^] | 1 | /*----------------------------------------------------------------------------*/ |
| 2 | /* Copyright (c) FIRST 2014. All Rights Reserved. */ |
| 3 | /* Open Source Software - may be modified and shared by FRC teams. The code */ |
| 4 | /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ |
| 5 | /*----------------------------------------------------------------------------*/ |
| 6 | |
| 7 | #include <stdlib.h> |
| 8 | #include <stdarg.h> |
| 9 | |
| 10 | #include "Vision/BaeUtilities.h" |
| 11 | #include "Vision/FrcError.h" |
| 12 | #include "Vision/VisionAPI.h" |
| 13 | |
| 14 | int VisionAPI_debugFlag = 1; |
| 15 | #define DPRINTF \ |
| 16 | if (VisionAPI_debugFlag) dprintf |
| 17 | |
| 18 | /** @file |
| 19 | * Image Management functions |
| 20 | */ |
| 21 | |
| 22 | /** |
| 23 | * @brief Create an image object |
| 24 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL, IMAQ_IMAGE_COMPLEX, |
| 25 | * IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL, IMAQ_IMAGE_RGB_U64 |
| 26 | * The border size is defaulted to 3 so that convolutional algorithms work at the |
| 27 | * edges. |
| 28 | * When you are finished with the created image, dispose of it by calling |
| 29 | * frcDispose(). |
| 30 | * To get extended error information, call GetLastError(). |
| 31 | * |
| 32 | * @param type Type of image to create |
| 33 | * @return Image* On success, this function returns the created image. On |
| 34 | * failure, it returns nullptr. |
| 35 | */ |
| 36 | Image* frcCreateImage(ImageType type) { |
| 37 | return imaqCreateImage(type, DEFAULT_BORDER_SIZE); |
| 38 | } |
| 39 | |
| 40 | /** |
| 41 | * @brief Dispose of one object. Supports any object created on the heap. |
| 42 | * |
| 43 | * @param object object to dispose of |
| 44 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 45 | * GetLastError(). |
| 46 | */ |
| 47 | int frcDispose(void* object) { return imaqDispose(object); } |
| 48 | /** |
| 49 | * @brief Dispose of a list of objects. Supports any object created on the heap. |
| 50 | * |
| 51 | * @param functionName The name of the function |
| 52 | * @param ... A list of pointers to structures that need to be disposed of. |
| 53 | * The last pointer in the list should always be set to nullptr. |
| 54 | * |
| 55 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 56 | * GetLastError(). |
| 57 | */ |
| 58 | int frcDispose(const char* functionName, ...) /* Variable argument list */ |
| 59 | { |
| 60 | va_list disposalPtrList; /* Input argument list */ |
| 61 | void* disposalPtr; /* For iteration */ |
| 62 | int success, returnValue = 1; |
| 63 | |
| 64 | va_start(disposalPtrList, functionName); /* start of variable list */ |
| 65 | disposalPtr = va_arg(disposalPtrList, void*); |
| 66 | while (disposalPtr != nullptr) { |
| 67 | success = imaqDispose(disposalPtr); |
| 68 | if (!success) { |
| 69 | returnValue = 0; |
| 70 | } |
| 71 | disposalPtr = va_arg(disposalPtrList, void*); |
| 72 | } |
| 73 | va_end(disposalPtrList); |
| 74 | return returnValue; |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * @brief Copy an image object. |
| 79 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL, IMAQ_IMAGE_RGB, |
| 80 | * IMAQ_IMAGE_HSL. |
| 81 | * |
| 82 | * @param dest Copy of image. On failure, dest is nullptr. Must have already been |
| 83 | * created using frcCreateImage(). |
| 84 | * When you are finished with the created image, dispose of it by calling |
| 85 | * frcDispose(). |
| 86 | * @param source Image to copy |
| 87 | * |
| 88 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 89 | * GetLastError(). |
| 90 | */ |
| 91 | int frcCopyImage(Image* dest, const Image* source) { |
| 92 | return imaqDuplicate(dest, source); |
| 93 | } |
| 94 | |
| 95 | /** |
| 96 | * @brief Crop image without changing the scale. |
| 97 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL, IMAQ_IMAGE_RGB, |
| 98 | * IMAQ_IMAGE_HSL. |
| 99 | * |
| 100 | * @param dest Modified image |
| 101 | * @param source Image to crop |
| 102 | * @param rect region to process, or IMAQ_NO_RECT |
| 103 | * |
| 104 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 105 | * GetLastError(). |
| 106 | */ |
| 107 | int frcCrop(Image* dest, const Image* source, Rect rect) { |
| 108 | return imaqScale(dest, source, 1, 1, IMAQ_SCALE_LARGER, rect); |
| 109 | } |
| 110 | |
| 111 | /** |
| 112 | * @brief Scales the entire image larger or smaller. |
| 113 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL, IMAQ_IMAGE_RGB, |
| 114 | * IMAQ_IMAGE_HSL. |
| 115 | * |
| 116 | * @param dest Modified image |
| 117 | * @param source Image to scale |
| 118 | * @param xScale the horizontal reduction ratio |
| 119 | * @param yScale the vertical reduction ratio |
| 120 | * @param scaleMode IMAQ_SCALE_LARGER or IMAQ_SCALE_SMALLER |
| 121 | * |
| 122 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 123 | * GetLastError(). |
| 124 | */ |
| 125 | int frcScale(Image* dest, const Image* source, int xScale, int yScale, |
| 126 | ScalingMode scaleMode) { |
| 127 | Rect rect = IMAQ_NO_RECT; |
| 128 | return imaqScale(dest, source, xScale, yScale, scaleMode, rect); |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * @brief Creates image object from the information in a file. The file can be |
| 133 | * in one of the following formats: |
| 134 | * PNG, JPEG, JPEG2000, TIFF, AIPD, or BMP. |
| 135 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL, IMAQ_IMAGE_COMPLEX, |
| 136 | * IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL, IMAQ_IMAGE_RGB_U64. |
| 137 | * |
| 138 | * @param image Image read in |
| 139 | * @param fileName File to read. Cannot be nullptr |
| 140 | * |
| 141 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 142 | * GetLastError(). |
| 143 | */ |
| 144 | int frcReadImage(Image* image, const char* fileName) { |
| 145 | return imaqReadFile(image, fileName, nullptr, nullptr); |
| 146 | } |
| 147 | |
| 148 | /** |
| 149 | * @brief Write image to a file. |
| 150 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL, IMAQ_IMAGE_COMPLEX, |
| 151 | * IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL, IMAQ_IMAGE_RGB_U64. |
| 152 | * |
| 153 | * The file type is determined by the extension, as follows: |
| 154 | * |
| 155 | * Extension File Type |
| 156 | * aipd or .apd AIPD |
| 157 | * .bmp BMP |
| 158 | * .jpg or .jpeg JPEG |
| 159 | * .jp2 JPEG2000 |
| 160 | * .png PNG |
| 161 | * .tif or .tiff TIFF |
| 162 | * |
| 163 | * |
| 164 | * The following are the supported image types for each file type: |
| 165 | * |
| 166 | * File Types Image Types |
| 167 | * AIPD all image types |
| 168 | * BMP, JPEG 8-bit, RGB |
| 169 | * PNG, TIFF, JPEG2000 8-bit, 16-bit, RGB, RGBU64 |
| 170 | * |
| 171 | * @param image Image to write |
| 172 | * @param fileName File to read. Cannot be nullptr. The extension determines the |
| 173 | * file format that is written. |
| 174 | * |
| 175 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 176 | * GetLastError(). |
| 177 | */ |
| 178 | int frcWriteImage(const Image* image, const char* fileName) { |
| 179 | RGBValue* colorTable = nullptr; |
| 180 | return imaqWriteFile(image, fileName, colorTable); |
| 181 | } |
| 182 | |
| 183 | /* Measure Intensity functions */ |
| 184 | |
| 185 | /** |
| 186 | * @brief Measures the pixel intensities in a rectangle of an image. |
| 187 | * Outputs intensity based statistics about an image such as Max, Min, Mean and |
| 188 | * Std Dev of pixel value. |
| 189 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL. |
| 190 | * |
| 191 | * Parameter Discussion : |
| 192 | * Relevant parameters of the HistogramReport include: |
| 193 | * min, max, mean and stdDev |
| 194 | * min/max Setting both min and max to 0 causes the function to set |
| 195 | * min to 0 |
| 196 | * and the max to 255 for 8-bit images and to the actual |
| 197 | * minimum value and |
| 198 | * maximum value of the image for all other image types. |
| 199 | * maxSetting both min and max to 0 causes the function to set max |
| 200 | * to 255 |
| 201 | * for 8-bit images and to the actual maximum value of the |
| 202 | * image for |
| 203 | * all other image types. |
| 204 | * |
| 205 | * @param image Image whose histogram the function calculates. |
| 206 | * @param numClasses The number of classes into which the function separates the |
| 207 | * pixels. |
| 208 | * Determines the number of elements in the histogram array returned |
| 209 | * @param min The minimum pixel value to consider for the histogram. |
| 210 | * The function does not count pixels with values less than min. |
| 211 | * @param max The maximum pixel value to consider for the histogram. |
| 212 | * The function does not count pixels with values greater than max. |
| 213 | * @param rect Region of interest in the image. If not included, the entire image |
| 214 | * is used. |
| 215 | * @return On success, this function returns a report describing the pixel value |
| 216 | * classification. |
| 217 | * When you are finished with the report, dispose of it by calling frcDispose(). |
| 218 | * On failure, this function returns nullptr. To get extended error information, |
| 219 | * call GetLastError(). |
| 220 | * |
| 221 | */ |
| 222 | HistogramReport* frcHistogram(const Image* image, int numClasses, float min, |
| 223 | float max) { |
| 224 | Rect rect = IMAQ_NO_RECT; |
| 225 | return frcHistogram(image, numClasses, min, max, rect); |
| 226 | } |
| 227 | HistogramReport* frcHistogram(const Image* image, int numClasses, float min, |
| 228 | float max, Rect rect) { |
| 229 | int success; |
| 230 | int fillValue = 1; |
| 231 | |
| 232 | /* create the region of interest */ |
| 233 | ROI* pRoi = imaqCreateROI(); |
| 234 | success = imaqAddRectContour(pRoi, rect); |
| 235 | if (!success) { |
| 236 | GetLastVisionError(); |
| 237 | return nullptr; |
| 238 | } |
| 239 | |
| 240 | /* make a mask from the ROI */ |
| 241 | Image* pMask = frcCreateImage(IMAQ_IMAGE_U8); |
| 242 | success = imaqROIToMask(pMask, pRoi, fillValue, nullptr, nullptr); |
| 243 | if (!success) { |
| 244 | GetLastVisionError(); |
| 245 | frcDispose(__FUNCTION__, pRoi, nullptr); |
| 246 | return nullptr; |
| 247 | } |
| 248 | |
| 249 | /* get a histogram report */ |
| 250 | HistogramReport* pHr = nullptr; |
| 251 | pHr = imaqHistogram(image, numClasses, min, max, pMask); |
| 252 | |
| 253 | /* clean up */ |
| 254 | frcDispose(__FUNCTION__, pRoi, pMask, nullptr); |
| 255 | |
| 256 | return pHr; |
| 257 | } |
| 258 | |
| 259 | /** |
| 260 | * @brief Calculates the histogram, or pixel distribution, of a color image. |
| 261 | * Supports IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL. |
| 262 | * |
| 263 | * @param image Image whose histogram the function calculates. |
| 264 | * @param numClasses The number of classes into which the function separates the |
| 265 | * pixels. |
| 266 | * Determines the number of elements in the histogram array returned |
| 267 | * @param mode The color space in which to perform the histogram. Possible values |
| 268 | * include IMAQ_RGB and IMAQ_HSL. |
| 269 | * @param mask An optional mask image. This image must be an IMAQ_IMAGE_U8 image. |
| 270 | * The function calculates the histogram using only those pixels in the image |
| 271 | * whose |
| 272 | * corresponding pixels in the mask are non-zero. Set this parameter to nullptr to |
| 273 | * calculate |
| 274 | * the histogram of the entire image, or use the simplified call. |
| 275 | * |
| 276 | * @return On success, this function returns a report describing the |
| 277 | * classification |
| 278 | * of each plane in a HistogramReport. |
| 279 | * When you are finished with the report, dispose of it by calling frcDispose(). |
| 280 | * On failure, this function returns nullptr. |
| 281 | * To get extended error information, call imaqGetLastError(). |
| 282 | */ |
| 283 | ColorHistogramReport* frcColorHistogram(const Image* image, int numClasses, |
| 284 | ColorMode mode) { |
| 285 | return frcColorHistogram(image, numClasses, mode, nullptr); |
| 286 | } |
| 287 | |
| 288 | ColorHistogramReport* frcColorHistogram(const Image* image, int numClasses, |
| 289 | ColorMode mode, Image* mask) { |
| 290 | return imaqColorHistogram2((Image*)image, numClasses, mode, nullptr, mask); |
| 291 | } |
| 292 | |
| 293 | /** |
| 294 | * @brief Measures the pixel intensities in a rectangle of an image. |
| 295 | * Outputs intensity based statistics about an image such as Max, Min, Mean and |
| 296 | * Std Dev of pixel value. |
| 297 | * Supports IMAQ_IMAGE_U8 (grayscale) IMAQ_IMAGE_RGB (color) IMAQ_IMAGE_HSL |
| 298 | * (color-HSL). |
| 299 | * |
| 300 | * @param image The image whose pixel value the function queries |
| 301 | * @param pixel The coordinates of the pixel that the function queries |
| 302 | * @param value On return, the value of the specified image pixel. This parameter |
| 303 | * cannot be nullptr. |
| 304 | * This data structure contains either grayscale, RGB, HSL, Complex or |
| 305 | * RGBU64Value depending on the type of image. |
| 306 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 307 | * GetLastError(). |
| 308 | */ |
| 309 | int frcGetPixelValue(const Image* image, Point pixel, PixelValue* value) { |
| 310 | return imaqGetPixel(image, pixel, value); |
| 311 | } |
| 312 | |
| 313 | /* Particle Analysis functions */ |
| 314 | |
| 315 | /** |
| 316 | * @brief Filters particles out of an image based on their measurements. |
| 317 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL. |
| 318 | * |
| 319 | * @param dest The destination image. If dest is used, it must be the same size |
| 320 | * as the Source image. It will contain only the filtered particles. |
| 321 | * @param source The image containing the particles to filter. |
| 322 | * @param criteria An array of criteria to apply to the particles in the source |
| 323 | * image. This array cannot be nullptr. |
| 324 | * See the NIVisionCVI.chm help file for definitions of criteria. |
| 325 | * @param criteriaCount The number of elements in the criteria array. |
| 326 | * @param options Binary filter options, including rejectMatches, rejectBorder, |
| 327 | * and connectivity8. |
| 328 | * @param rect Area of image to filter. If omitted, the default is entire image. |
| 329 | * @param numParticles On return, the number of particles left in the image |
| 330 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 331 | * GetLastError(). |
| 332 | */ |
| 333 | int frcParticleFilter(Image* dest, Image* source, |
| 334 | const ParticleFilterCriteria2* criteria, |
| 335 | int criteriaCount, const ParticleFilterOptions* options, |
| 336 | int* numParticles) { |
| 337 | Rect rect = IMAQ_NO_RECT; |
| 338 | return frcParticleFilter(dest, source, criteria, criteriaCount, options, rect, |
| 339 | numParticles); |
| 340 | } |
| 341 | |
| 342 | int frcParticleFilter(Image* dest, Image* source, |
| 343 | const ParticleFilterCriteria2* criteria, |
| 344 | int criteriaCount, const ParticleFilterOptions* options, |
| 345 | Rect rect, int* numParticles) { |
| 346 | ROI* roi = imaqCreateROI(); |
| 347 | imaqAddRectContour(roi, rect); |
| 348 | return imaqParticleFilter3(dest, source, criteria, criteriaCount, options, |
| 349 | roi, numParticles); |
| 350 | } |
| 351 | |
| 352 | /** |
| 353 | * @brief Performs morphological transformations on binary images. |
| 354 | * Supports IMAQ_IMAGE_U8. |
| 355 | * |
| 356 | * @param dest The destination image. The border size of the destination image is |
| 357 | * not important. |
| 358 | * @param source The image on which the function performs the morphological |
| 359 | * operations. The calculation |
| 360 | * modifies the border of the source image. The border must be at least half as |
| 361 | * large as the larger |
| 362 | * dimension of the structuring element. The connected source image for a |
| 363 | * morphological transformation |
| 364 | * must have been created with a border capable of supporting the size of the |
| 365 | * structuring element. |
| 366 | * A 3 by 3 structuring element requires a minimal border of 1, a 5 by 5 |
| 367 | * structuring element requires a minimal border of 2, and so on. |
| 368 | * @param method The morphological transform to apply. |
| 369 | * @param structuringElement The structuring element used in the operation. Omit |
| 370 | * this parameter if you do not want a custom structuring element. |
| 371 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 372 | * GetLastError(). |
| 373 | */ |
| 374 | int frcMorphology(Image* dest, Image* source, MorphologyMethod method) { |
| 375 | return imaqMorphology(dest, source, method, nullptr); |
| 376 | } |
| 377 | |
| 378 | int frcMorphology(Image* dest, Image* source, MorphologyMethod method, |
| 379 | const StructuringElement* structuringElement) { |
| 380 | return imaqMorphology(dest, source, method, structuringElement); |
| 381 | } |
| 382 | |
| 383 | /** |
| 384 | * @brief Eliminates particles that touch the border of the image. |
| 385 | * Supports IMAQ_IMAGE_U8. |
| 386 | * |
| 387 | * @param dest The destination image. |
| 388 | * @param source The source image. If the image has a border, the function sets |
| 389 | * all border pixel values to 0. |
| 390 | * @param connectivity8 specifies the type of connectivity used by the algorithm |
| 391 | * for particle detection. |
| 392 | * The connectivity mode directly determines whether an adjacent pixel belongs to |
| 393 | * the same particle or a |
| 394 | * different particle. Set to TRUE to use connectivity-8 to determine whether |
| 395 | * particles are touching |
| 396 | * Set to FALSE to use connectivity-4 to determine whether particles are |
| 397 | * touching. |
| 398 | * The default setting for the simplified call is TRUE |
| 399 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 400 | * GetLastError(). |
| 401 | */ |
| 402 | int frcRejectBorder(Image* dest, Image* source) { |
| 403 | return imaqRejectBorder(dest, source, TRUE); |
| 404 | } |
| 405 | |
| 406 | int frcRejectBorder(Image* dest, Image* source, int connectivity8) { |
| 407 | return imaqRejectBorder(dest, source, connectivity8); |
| 408 | } |
| 409 | |
| 410 | /** |
| 411 | * @brief Counts the number of particles in a binary image. |
| 412 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL. |
| 413 | * @param image binary (thresholded) image |
| 414 | * @param numParticles On return, the number of particles. |
| 415 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 416 | * GetLastError(). |
| 417 | */ |
| 418 | int frcCountParticles(Image* image, int* numParticles) { |
| 419 | return imaqCountParticles(image, 1, numParticles); |
| 420 | } |
| 421 | |
| 422 | /** |
| 423 | * @brief Conduct measurements for a single particle in an images. |
| 424 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16, IMAQ_IMAGE_SGL. |
| 425 | * |
| 426 | * @param image image with the particle to analyze. This function modifies the |
| 427 | * source image. |
| 428 | * If you need the original image, create a copy of the image using frcCopy() |
| 429 | * before using this function. |
| 430 | * @param particleNumber The number of the particle to get information on |
| 431 | * @param par on return, a particle analysis report containing information about |
| 432 | * the particle. This structure must be created by the caller. |
| 433 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 434 | * GetLastError(). |
| 435 | */ |
| 436 | int frcParticleAnalysis(Image* image, int particleNumber, |
| 437 | ParticleAnalysisReport* par) { |
| 438 | int success = 0; |
| 439 | |
| 440 | /* image information */ |
| 441 | int height, width; |
| 442 | if (!imaqGetImageSize(image, &width, &height)) { |
| 443 | return success; |
| 444 | } |
| 445 | par->imageWidth = width; |
| 446 | par->imageHeight = height; |
| 447 | par->particleIndex = particleNumber; |
| 448 | |
| 449 | /* center of mass point of the largest particle */ |
| 450 | double returnDouble; |
| 451 | success = imaqMeasureParticle(image, particleNumber, 0, |
| 452 | IMAQ_MT_CENTER_OF_MASS_X, &returnDouble); |
| 453 | if (!success) { |
| 454 | return success; |
| 455 | } |
| 456 | par->center_mass_x = (int)returnDouble; // pixel |
| 457 | |
| 458 | success = imaqMeasureParticle(image, particleNumber, 0, |
| 459 | IMAQ_MT_CENTER_OF_MASS_Y, &returnDouble); |
| 460 | if (!success) { |
| 461 | return success; |
| 462 | } |
| 463 | par->center_mass_y = (int)returnDouble; // pixel |
| 464 | |
| 465 | /* particle size statistics */ |
| 466 | success = imaqMeasureParticle(image, particleNumber, 0, IMAQ_MT_AREA, |
| 467 | &returnDouble); |
| 468 | if (!success) { |
| 469 | return success; |
| 470 | } |
| 471 | par->particleArea = returnDouble; |
| 472 | |
| 473 | success = imaqMeasureParticle(image, particleNumber, 0, |
| 474 | IMAQ_MT_BOUNDING_RECT_TOP, &returnDouble); |
| 475 | if (!success) { |
| 476 | return success; |
| 477 | } |
| 478 | par->boundingRect.top = (int)returnDouble; |
| 479 | |
| 480 | success = imaqMeasureParticle(image, particleNumber, 0, |
| 481 | IMAQ_MT_BOUNDING_RECT_LEFT, &returnDouble); |
| 482 | if (!success) { |
| 483 | return success; |
| 484 | } |
| 485 | par->boundingRect.left = (int)returnDouble; |
| 486 | |
| 487 | success = imaqMeasureParticle(image, particleNumber, 0, |
| 488 | IMAQ_MT_BOUNDING_RECT_HEIGHT, &returnDouble); |
| 489 | if (!success) { |
| 490 | return success; |
| 491 | } |
| 492 | par->boundingRect.height = (int)returnDouble; |
| 493 | |
| 494 | success = imaqMeasureParticle(image, particleNumber, 0, |
| 495 | IMAQ_MT_BOUNDING_RECT_WIDTH, &returnDouble); |
| 496 | if (!success) { |
| 497 | return success; |
| 498 | } |
| 499 | par->boundingRect.width = (int)returnDouble; |
| 500 | |
| 501 | /* particle quality statistics */ |
| 502 | success = imaqMeasureParticle(image, particleNumber, 0, |
| 503 | IMAQ_MT_AREA_BY_IMAGE_AREA, &returnDouble); |
| 504 | if (!success) { |
| 505 | return success; |
| 506 | } |
| 507 | par->particleToImagePercent = returnDouble; |
| 508 | |
| 509 | success = imaqMeasureParticle(image, particleNumber, 0, |
| 510 | IMAQ_MT_AREA_BY_PARTICLE_AND_HOLES_AREA, |
| 511 | &returnDouble); |
| 512 | if (!success) { |
| 513 | return success; |
| 514 | } |
| 515 | par->particleQuality = returnDouble; |
| 516 | |
| 517 | /* normalized position (-1 to 1) */ |
| 518 | par->center_mass_x_normalized = RangeToNormalized(par->center_mass_x, width); |
| 519 | par->center_mass_y_normalized = RangeToNormalized(par->center_mass_y, height); |
| 520 | |
| 521 | return success; |
| 522 | } |
| 523 | |
| 524 | /* Image Enhancement functions */ |
| 525 | |
| 526 | /** |
| 527 | * @brief Improves contrast on a grayscale image. |
| 528 | * Supports IMAQ_IMAGE_U8, IMAQ_IMAGE_I16. |
| 529 | * @param dest The destination image. |
| 530 | * @param source The image to equalize |
| 531 | * @param min the smallest value used for processing. After processing, all pixel |
| 532 | * values that are less than or equal to the Minimum in the original image are set |
| 533 | * to 0 for an 8-bit image. In 16-bit and floating-point images, these pixel |
| 534 | * values are set to the smallest pixel value found in the original image. |
| 535 | * @param max the largest value used for processing. After processing, all pixel |
| 536 | * values that are greater than or equal to the Maximum in the original image are |
| 537 | * set to 255 for an 8-bit image. In 16-bit and floating-point images, these pixel |
| 538 | * values are set to the largest pixel value found in the original image. |
| 539 | * @param mask an 8-bit image that specifies the region of the small image that |
| 540 | * will be copied. Only those pixels in the Image Src (Small) image that |
| 541 | * correspond to an equivalent non-zero pixel in the mask image are copied. All |
| 542 | * other pixels keep their original values. The entire image is processed if Image |
| 543 | * Mask is nullptr or this parameter is omitted. |
| 544 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 545 | * GetLastError(). |
| 546 | * |
| 547 | * option defaults: |
| 548 | * searchRect = IMAQ_NO_RECT |
| 549 | * minMatchScore = DEFAULT_MINMAX_SCORE (800) |
| 550 | */ |
| 551 | int frcEqualize(Image* dest, const Image* source, float min, float max) { |
| 552 | return frcEqualize(dest, source, min, max, nullptr); |
| 553 | } |
| 554 | |
| 555 | int frcEqualize(Image* dest, const Image* source, float min, float max, |
| 556 | const Image* mask) { |
| 557 | return imaqEqualize(dest, source, min, max, mask); |
| 558 | } |
| 559 | |
| 560 | /** |
| 561 | * @brief Improves contrast on a color image. |
| 562 | * Supports IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL |
| 563 | * |
| 564 | * option defaults: colorEqualization = TRUE to equalize all three planes of the |
| 565 | * image |
| 566 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 567 | * GetLastError(). |
| 568 | * @param dest The destination image. |
| 569 | * @param source The image to equalize |
| 570 | * @param colorEqualization Set this parameter to TRUE to equalize all three |
| 571 | * planes of the image (the default). Set this parameter to FALSE to equalize only |
| 572 | * the luminance plane. |
| 573 | */ |
| 574 | int frcColorEqualize(Image* dest, const Image* source) { |
| 575 | return imaqColorEqualize(dest, source, TRUE); |
| 576 | } |
| 577 | |
| 578 | int frcColorEqualize(Image* dest, const Image* source, int colorEqualization) { |
| 579 | return imaqColorEqualize(dest, source, TRUE); |
| 580 | } |
| 581 | |
| 582 | /* Image Conversion functions */ |
| 583 | |
| 584 | /** |
| 585 | * @brief Automatically thresholds a grayscale image into a binary image for |
| 586 | * Particle Analysis based on a smart threshold. |
| 587 | * Supports IMAQ_IMAGE_RGB, IMAQ_IMAGE_I16 |
| 588 | * @param dest The destination image. |
| 589 | * @param source The image to threshold |
| 590 | * @param windowWidth The width of the rectangular window around the pixel on |
| 591 | * which the function |
| 592 | * performs the local threshold. This number must be at least 3 and cannot be |
| 593 | * larger than the width of source |
| 594 | * @param windowHeight The height of the rectangular window around the pixel on |
| 595 | * which the function |
| 596 | * performs the local threshold. This number must be at least 3 and cannot be |
| 597 | * larger than the height of source |
| 598 | * @param method Specifies the local thresholding method the function uses. Value |
| 599 | * can be IMAQ_NIBLACK |
| 600 | * (which computes thresholds for each pixel based on its local statistics using |
| 601 | * the Niblack local thresholding |
| 602 | * algorithm.), or IMAQ_BACKGROUND_CORRECTION (which does background correction |
| 603 | * first to eliminate non-uniform |
| 604 | * lighting effects, then performs thresholding using the Otsu thresholding |
| 605 | * algorithm) |
| 606 | * @param deviationWeight Specifies the k constant used in the Niblack local |
| 607 | * thresholding algorithm, which |
| 608 | * determines the weight applied to the variance calculation. Valid k constants |
| 609 | * range from 0 to 1. Setting |
| 610 | * this value to 0 will increase the performance of the function because the |
| 611 | * function will not calculate the |
| 612 | * variance for any of the pixels. The function ignores this value if method is |
| 613 | * not set to IMAQ_NIBLACK |
| 614 | * @param type Specifies the type of objects for which you want to look. Values |
| 615 | * can be IMAQ_BRIGHT_OBJECTS |
| 616 | * or IMAQ_DARK_OBJECTS. |
| 617 | * @param replaceValue Specifies the replacement value the function uses for the |
| 618 | * pixels of the kept objects |
| 619 | * in the destination image. |
| 620 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 621 | * GetLastError(). |
| 622 | */ |
| 623 | int frcSmartThreshold(Image* dest, const Image* source, |
| 624 | unsigned int windowWidth, unsigned int windowHeight, |
| 625 | LocalThresholdMethod method, double deviationWeight, |
| 626 | ObjectType type) { |
| 627 | float replaceValue = 1.0; |
| 628 | return imaqLocalThreshold(dest, source, windowWidth, windowHeight, method, |
| 629 | deviationWeight, type, replaceValue); |
| 630 | } |
| 631 | |
| 632 | int frcSmartThreshold(Image* dest, const Image* source, |
| 633 | unsigned int windowWidth, unsigned int windowHeight, |
| 634 | LocalThresholdMethod method, double deviationWeight, |
| 635 | ObjectType type, float replaceValue) { |
| 636 | return imaqLocalThreshold(dest, source, windowWidth, windowHeight, method, |
| 637 | deviationWeight, type, replaceValue); |
| 638 | } |
| 639 | |
| 640 | /** |
| 641 | * @brief Converts a grayscale image to a binary image for Particle Analysis |
| 642 | * based on a fixed threshold. |
| 643 | * The function sets pixels values outside of the given range to 0. The function |
| 644 | * sets pixel values |
| 645 | * within the range to a given value or leaves the values unchanged. |
| 646 | * Use the simplified call to leave pixel values unchanged. |
| 647 | * Supports IMAQ_IMAGE_RGB, IMAQ_IMAGE_I16. |
| 648 | * |
| 649 | * @param dest The destination image. |
| 650 | * @param source The image to threshold |
| 651 | * @param rangeMin The lower boundary of the range of pixel values to keep |
| 652 | * @param rangeMax The upper boundary of the range of pixel values to keep. |
| 653 | * |
| 654 | * @return int - error code: 0 = error. To get extended error information, call |
| 655 | * GetLastError(). |
| 656 | */ |
| 657 | int frcSimpleThreshold(Image* dest, const Image* source, float rangeMin, |
| 658 | float rangeMax) { |
| 659 | int newValue = 255; |
| 660 | return frcSimpleThreshold(dest, source, rangeMin, rangeMax, newValue); |
| 661 | } |
| 662 | |
| 663 | /** |
| 664 | * @brief Converts a grayscale image to a binary image for Particle Analysis |
| 665 | * based on a fixed threshold. |
| 666 | * The function sets pixels values outside of the given range to 0. The function |
| 667 | * sets |
| 668 | * pixel values within the range to the given value. |
| 669 | * Supports IMAQ_IMAGE_RGB, IMAQ_IMAGE_I16. |
| 670 | * |
| 671 | * @param dest The destination image. |
| 672 | * @param source The image to threshold |
| 673 | * @param rangeMin The lower boundary of the range of pixel values to keep |
| 674 | * @param rangeMax The upper boundary of the range of pixel values to keep. |
| 675 | * @param newValue The replacement value for pixels within the range. Use the |
| 676 | * simplified call to leave the pixel values unchanged |
| 677 | * |
| 678 | * @return int - error code: 0 = error. To get extended error information, call |
| 679 | * GetLastError(). |
| 680 | */ |
| 681 | int frcSimpleThreshold(Image* dest, const Image* source, float rangeMin, |
| 682 | float rangeMax, float newValue) { |
| 683 | int useNewValue = TRUE; |
| 684 | return imaqThreshold(dest, source, rangeMin, rangeMax, useNewValue, newValue); |
| 685 | } |
| 686 | |
| 687 | /** |
| 688 | * @brief Applies a threshold to the Red, Green, and Blue values of a RGB image |
| 689 | * or the Hue, |
| 690 | * Saturation, Luminance values for a HSL image. |
| 691 | * Supports IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL. |
| 692 | * This simpler version filters based on a hue range in the HSL mode. |
| 693 | * |
| 694 | * @param dest The destination image. This must be a IMAQ_IMAGE_U8 image. |
| 695 | * @param source The image to threshold |
| 696 | * @param mode The color space to perform the threshold in. valid values are: |
| 697 | * IMAQ_RGB, IMAQ_HSL. |
| 698 | * @param plane1Range The selection range for the first plane of the image. Set |
| 699 | * this parameter to nullptr to use a selection range from 0 to 255. |
| 700 | * @param plane2Range The selection range for the second plane of the image. Set |
| 701 | * this parameter to nullptr to use a selection range from 0 to 255. |
| 702 | * @param plane3Range The selection range for the third plane of the image. Set |
| 703 | * this parameter to nullptr to use a selection range from 0 to 255. |
| 704 | * |
| 705 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 706 | * GetLastError(). |
| 707 | * */ |
| 708 | int frcColorThreshold(Image* dest, const Image* source, ColorMode mode, |
| 709 | const Range* plane1Range, const Range* plane2Range, |
| 710 | const Range* plane3Range) { |
| 711 | int replaceValue = 1; |
| 712 | return imaqColorThreshold(dest, source, replaceValue, mode, plane1Range, |
| 713 | plane2Range, plane3Range); |
| 714 | } |
| 715 | |
| 716 | /** |
| 717 | * @brief Applies a threshold to the Red, Green, and Blue values of a RGB image |
| 718 | * or the Hue, |
| 719 | * Saturation, Luminance values for a HSL image. |
| 720 | * Supports IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL. |
| 721 | * The simpler version filters based on a hue range in the HSL mode. |
| 722 | * |
| 723 | * @param dest The destination image. This must be a IMAQ_IMAGE_U8 image. |
| 724 | * @param source The image to threshold |
| 725 | * @param replaceValue Value to assign to selected pixels. Defaults to 1 if |
| 726 | * simplified call is used. |
| 727 | * @param mode The color space to perform the threshold in. valid values are: |
| 728 | * IMAQ_RGB, IMAQ_HSL. |
| 729 | * @param plane1Range The selection range for the first plane of the image. Set |
| 730 | * this parameter to nullptr to use a selection range from 0 to 255. |
| 731 | * @param plane2Range The selection range for the second plane of the image. Set |
| 732 | * this parameter to nullptr to use a selection range from 0 to 255. |
| 733 | * @param plane3Range The selection range for the third plane of the image. Set |
| 734 | * this parameter to nullptr to use a selection range from 0 to 255. |
| 735 | * |
| 736 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 737 | * GetLastError(). |
| 738 | */ |
| 739 | int frcColorThreshold(Image* dest, const Image* source, int replaceValue, |
| 740 | ColorMode mode, const Range* plane1Range, |
| 741 | const Range* plane2Range, const Range* plane3Range) { |
| 742 | return imaqColorThreshold(dest, source, replaceValue, mode, plane1Range, |
| 743 | plane2Range, plane3Range); |
| 744 | } |
| 745 | |
| 746 | /** |
| 747 | * @brief A simpler version of ColorThreshold that thresholds hue range in the |
| 748 | * HSL mode. Supports IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL. |
| 749 | * @param dest The destination image. |
| 750 | * @param source The image to threshold |
| 751 | * @param hueRange The selection range for the hue (color). |
| 752 | * @param minSaturation The minimum saturation value (1-255). If not used, |
| 753 | * DEFAULT_SATURATION_THRESHOLD is the default. |
| 754 | * |
| 755 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 756 | * GetLastError(). |
| 757 | */ |
| 758 | int frcHueThreshold(Image* dest, const Image* source, const Range* hueRange) { |
| 759 | return frcHueThreshold(dest, source, hueRange, DEFAULT_SATURATION_THRESHOLD); |
| 760 | } |
| 761 | |
| 762 | int frcHueThreshold(Image* dest, const Image* source, const Range* hueRange, |
| 763 | int minSaturation) { |
| 764 | // assume HSL mode |
| 765 | ColorMode mode = IMAQ_HSL; |
| 766 | // Set saturation 100 - 255 |
| 767 | Range satRange; |
| 768 | satRange.minValue = minSaturation; |
| 769 | satRange.maxValue = 255; |
| 770 | // Set luminance 100 - 255 |
| 771 | Range lumRange; |
| 772 | lumRange.minValue = 100; |
| 773 | lumRange.maxValue = 255; |
| 774 | // Replace pixels with 1 if pass threshold filter |
| 775 | int replaceValue = 1; |
| 776 | return imaqColorThreshold(dest, source, replaceValue, mode, hueRange, |
| 777 | &satRange, &lumRange); |
| 778 | } |
| 779 | |
| 780 | /** |
| 781 | * @brief Extracts the Red, Green, Blue, or Hue, Saturation or Luminance |
| 782 | * information from a color image. |
| 783 | * Supports IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL, IMAQ_IMAGE_RGB_U64. |
| 784 | * |
| 785 | * @param image The source image that the function extracts the planes from. |
| 786 | * @param mode The color space that the function extracts the planes from. Valid |
| 787 | * values are IMAQ_RGB, IMAQ_HSL, IMAQ_HSV, IMAQ_HSI. |
| 788 | * @param plane1 On return, the first extracted plane. Set this parameter to nullptr |
| 789 | * if you do not need this information. RGB-Red, HSL/HSV/HSI-Hue. |
| 790 | * @param plane2 On return, the second extracted plane. Set this parameter to |
| 791 | * nullptr if you do not need this information. RGB-Green, HSL/HSV/HSI-Saturation. |
| 792 | * @param plane3 On return, the third extracted plane. Set this parameter to nullptr |
| 793 | * if you do not need this information. RGB-Blue, HSL-Luminance, HSV-Value, |
| 794 | * HSI-Intensity. |
| 795 | * |
| 796 | * @return error code: 0 = error. To get extended error information, call |
| 797 | * GetLastError(). |
| 798 | */ |
| 799 | int frcExtractColorPlanes(const Image* image, ColorMode mode, Image* plane1, |
| 800 | Image* plane2, Image* plane3) { |
| 801 | return imaqExtractColorPlanes(image, mode, plane1, plane2, plane3); |
| 802 | } |
| 803 | |
| 804 | /** |
| 805 | * @brief Extracts the Hue information from a color image. Supports |
| 806 | * IMAQ_IMAGE_RGB, IMAQ_IMAGE_HSL, IMAQ_IMAGE_RGB_U64 |
| 807 | * |
| 808 | * @param image The source image that the function extracts the plane from. |
| 809 | * @param huePlane On return, the extracted hue plane. |
| 810 | * @param minSaturation the minimum saturation level required 0-255 (try 50) |
| 811 | * |
| 812 | * @return On success: 1. On failure: 0. To get extended error information, call |
| 813 | * GetLastError(). |
| 814 | */ |
| 815 | int frcExtractHuePlane(const Image* image, Image* huePlane) { |
| 816 | return frcExtractHuePlane(image, huePlane, DEFAULT_SATURATION_THRESHOLD); |
| 817 | } |
| 818 | |
| 819 | int frcExtractHuePlane(const Image* image, Image* huePlane, int minSaturation) { |
| 820 | return frcExtractColorPlanes(image, IMAQ_HSL, huePlane, nullptr, nullptr); |
| 821 | } |