Check Color Range
In this sample, the function F_VN_CheckColorRange searches for red, green and blue objects in the image and labels them according to their color. The function is applied to either RGB or HSV images. It is also possible to apply this function to images in other color spaces, such as Lab, BGR, or YCrCb. In such cases, the image conversion and threshold parameterization must be adapted accordingly.
Explanation
The code allows the choice of color space for color range segmentation. The variable eColorSpace can be used to switch between the two variants, RGB and HSV. Depending on the selected color space, different threshold arrays (aColorRefLowRGB/aColorRefUpRGB for RGB or aColorRefLowHSV/aColorRefUpHSV for HSV) are used. The variables contain the respectively defined lower and upper limit values for the three colors to be detected (red, green, blue). The references refColorLow and refColorUp refer to the respective active arrays.
The input image is in Bayer RG format and is converted into an RGB image using the F_VN_ConvertColorSpace function. In RGB mode, the converted image is used directly, while in HSV mode an additional color space conversion from RGB to HSV is carried out with the transformation TCVN_CST_RGB_TO_HSV_FULL. The HSV_FULL variant is selected so that the Hue channel uses the full 8-bit value range (0-255) instead of being limited to 0-179 as with HSV, which enables finer parameterization. The HSV color space often provides more reliable results in uneven lighting conditions, as the color values (Hue) are separated from the color saturation and brightness (Value). In the additive RGB color space, a change in brightness usually leads to value changes in all 3 channels, which makes it difficult to define threshold values for differentiation.
Finally, the F_VN_CheckColorRange function can be used with the respective upper and lower threshold values.
Variables
eColorSpace : (RGB, HSV); // Selected color space
hr : HRESULT;
// Images
ipImageIn : ITcVnImage;
ipImageInDisp : ITcVnDisplayableImage;
ipImageColorSpace : ITcVnImage;
ipImageColorSpaceDisp : ITcVnDisplayableImage;
ipImageWorkCol : ITcVnImage;
ipImageWorkColDisp : ARRAY [0..2] OF ITcVnDisplayableImage;
ipImageRes : ITcVnImage;
ipImageResDisp : ITcVnDisplayableImage;
// Colors
iColor : INT;
aColorTxt : ARRAY[0..2] OF STRING := [ 'RED', 'GREEN', 'BLUE' ];
aColor : ARRAY[0..2] OF TcVnVector4_LREAL := [ [150, 0, 0], [0, 255, 0], [0, 0, 255] ];
refColorBoundsLow : REFERENCE TO ARRAY[0..2] OF TcVnVector4_LREAL;
refColorBoundsUp : REFERENCE TO ARRAY[0..2] OF TcVnVector4_LREAL;
// Bounds values for RGB
aColorBoundsLowRGB : ARRAY[0..2] OF TcVnVector4_LREAL := [ [150, 50, 20], [35, 90, 60], [20, 40, 130] ];
aColorBoundsUpRGB : ARRAY[0..2] OF TcVnVector4_LREAL := [ [255, 120, 100], [100, 200, 140], [60, 160, 255] ];
// Bounds values for HSV
aColorBoundsLowHSV : ARRAY[0..2] OF TcVnVector4_LREAL := [ [251, 180, 205], [103, 150, 100], [130, 180, 130] ];
aColorBoundsUpHSV : ARRAY[0..2] OF TcVnVector4_LREAL := [ [6, 220, 255], [113, 190, 190], [149, 230, 210] ];
// Contours
ipContourList : ITcVnContainer;
ipIterator : ITcVnForwardIterator;
ipContour : ITcVnContainer;
fArea : LREAL;
aCenter : TcVnPoint2_LREAL;Code
// Attention: With other images another color space transformation could be necessary
hr := F_VN_ConvertColorSpace(ipImageIn, ipImageRes, TCVN_CST_Bayer_RG_TO_RGB, hr);
// Select the color space for segmentation
CASE eColorSpace OF
RGB:
hr := F_VN_CopyImage(ipImageRes, ipImageColorSpace, hr);
refColorBoundsLow REF= aColorBoundsLowRGB;
refColorBoundsUp REF= aColorBoundsUpRGB;
HSV:
hr := F_VN_ConvertColorSpace(ipImageRes, ipImageColorSpace, TCVN_CST_RGB_TO_HSV_FULL, hr);
refColorBoundsLow REF= aColorBoundsLowHSV;
refColorBoundsUp REF= aColorBoundsUpHSV;
END_CASE
FOR iColor := 0 TO 2 DO
// Apply a "Color-Threshold" on the image
hr := F_VN_CheckColorRange(ipImageColorSpace, ipImageWorkCol, refColorBoundsLow[iColor], refColorBoundsUp[iColor], hr);
// Find all objects / contours in the black and white image
hr := F_VN_FindContours(ipImageWorkCol, ipContourList, hr);
hr := F_VN_GetForwardIterator(ipContourList, ipIterator, hr);
// Filter the objects by size and draw the contours
WHILE SUCCEEDED(hr) AND_THEN ipIterator.CheckIfEnd() <> S_OK DO
hr := F_VN_GetContainer(ipIterator, ipContour, hr);
hr := F_VN_IncrementIterator(ipIterator, hr);
// Filter contours by size
hr := F_VN_ContourArea(ipContour, fArea, hr);
IF fArea > 5000 THEN
// Draw Results into an Image
hr := F_VN_DrawContours(ipContour, -1, ipImageRes, aColor[iColor], 3, hr);
hr := F_VN_ContourCenterOfMass(ipContour, aCenter, hr);
hr := F_VN_PutText(aColorTxt[iColor], ipImageRes, LREAL_TO_UDINT(aCenter[0])-30, LREAL_TO_UDINT(aCenter[1])+10, TCVN_FT_HERSHEY_PLAIN, 2, aColor[iColor], hr);
END_IF
END_WHILE
// Display effect of the CheckColorRange-Function
hr := F_VN_TransformIntoDisplayableImage(ipImageWorkCol, ipImageWorkColDisp[iColor], hr);
END_FORResult
In ipImageColorSpaceDisp the selected color space is displayed in the ADS Image Watch. This enables the analysis of the exact pixel values to optimize the threshold value parameterization. The HSV image is displayed in false colors, as the H, S and V channels are interpreted as RGB.

The binary images ipImageWorkColDisp[0..2] show the segmentation results for each color. If RGB is chosen as the color space, artifacts are often visible at the edges of the object. This is because all three color channels are linked to the brightness. As a result, lighting gradients and highlights on object edges can change the color values to such an extent that they fall within or outside the segmentation range in an undesirable way. The HSV color space generally provides cleaner segmentations, as the threshold values for brightness (Value) and saturation can be set separately from the color information (Hue).
When checking the color range of red tones in the HSV color space, F_VN_CheckColorRange can correctly process the so-called "wraparound problem" of the Hue channel, as the red range extends approx. +-20° around 0°. If the lower limit value for the hue is defined as greater than the upper limit value (e.g. 251 to 6), the function automatically recognizes this as a circular area across the zero point. This eliminates the need to manually split into two separate color ranges and function calls and enables the entire color range to be detected in a single step.

The results image ipImageResDisp shows the detected objects with colored contours and labels corresponding to their detected color.
