# Revision history [back]

Just an update to this code, as of today, the InRange function still does not exist for GPU.

The above code only does a threshold, i.e. it only evaluates a minimum floor value and ignores the ceiling..

There are two reasons, one is that the threshold function does not use a ceiling, only a floor.. the "maxval" parameter is actually what binary threshold wil use to replace the current value when threshold is met..

For example: a value of 23 with at a threshold of 50 and maxval of 100 will become 0. a value of 57 with a threshold of 50 and maxval of 100 will become 100 a value of 200 with a threshold of 50 and maxal of 100 will become 100

Meaning that any input value that falls above the threshold will be replaced with the maxval..

So - In order to really implement an "InRange" function you need to zero out values that are below your floor AND above your ceiling and then make everything within that range = maxval

The way to do this is to do use two thresholds, one for floor and one for ceiling and then only keep the data that falls between the two.

Like this:

//low and high ranges
cv::Scalar hsv_low(20, 70, 120);
cv::Scalar hsv_high(50, 200, 255);

cv::cuda::GpuMat src_img_gpu(src_img);

//all the parts to keep low and high thresholds
cv::cuda::GpuMat mat_parts[3];
cv::cuda::GpuMat mat_parts_low[3];
cv::cuda::GpuMat mat_parts_high[3];

//split into 3 channels H, S and V
cv::cuda::split(src_img_gpu, mat_parts);

//Use the inverse binary of upper threshold with bitwise_and to remove above limit values from lower threshold.

//find range between high and low values of H
cv::cuda::threshold(mat_parts[0], mat_parts_low[0], hsv_low[0], MAX_UCHAR, cv::THRESH_BINARY);
cv::cuda::threshold(mat_parts[0], mat_parts_high[0],  hsv_high[0], MAX_UCHAR, cv::THRESH_BINARY_INV);
cv::cuda::bitwise_and(mat_parts_high[0], mat_parts_low[0], mat_parts[0]);

//find range between high and low values of S
cv::cuda::threshold(mat_parts[1], mat_parts_low[1], hsv_low[1], MAX_UCHAR, cv::THRESH_BINARY);
cv::cuda::threshold(mat_parts[1], mat_parts_high[1],  hsv_high[1], MAX_UCHAR, cv::THRESH_BINARY_INV);
cv::cuda::bitwise_and(mat_parts_high[1], mat_parts_low[1], mat_parts[1]);

//find range between high and low values of V
cv::cuda::threshold(mat_parts[2], mat_parts_low[2], hsv_low[2], MAX_UCHAR, cv::THRESH_BINARY);
cv::cuda::threshold(mat_parts[2], mat_parts_high[2],  hsv_high[2], MAX_UCHAR, cv::THRESH_BINARY_INV);
cv::cuda::bitwise_and(mat_parts_high[2], mat_parts_low[2], mat_parts[2]);

//bitwise AND all channels.
cv::cuda::bitwise_and(mat_parts[0], mat_parts[1], tmp3);
cv::cuda::bitwise_and(tmp3, mat_parts[2], tmp4);


Just an update to this code, as of today, the InRange function still does not exist for GPU.

The above code only does a threshold, i.e. it only evaluates a minimum floor value and ignores the ceiling..

There are two reasons, one is that the threshold function does not use a ceiling, only a floor.. the "maxval" parameter is actually what binary threshold wil use to replace the current value when threshold is met..

For example: a value of 23 with at a threshold of 50 and maxval of 100 will become 0. a value of 57 with a threshold of 50 and maxval of 100 will become 100 a value of 200 with a threshold of 50 and maxal of 100 will become 100

Meaning that any input value that falls above the threshold will be replaced with the maxval..

So - In order to really implement an "InRange" function you need to zero out values that are below your floor AND above your ceiling and then make everything within that range = maxval

The way to do this is to do use two thresholds, one for floor and one for ceiling and then only keep the data that falls between the two.

Like this:

//low and high ranges
cv::Scalar hsv_low(20, 70, 120);
cv::Scalar hsv_high(50, 200, 255);

cv::cuda::GpuMat src_img_gpu(src_img);

//all the parts to keep low and high thresholds
cv::cuda::GpuMat mat_parts[3];
cv::cuda::GpuMat mat_parts_low[3];
cv::cuda::GpuMat mat_parts_high[3];

//split into 3 channels H, S and V
cv::cuda::split(src_img_gpu, mat_parts);

//Use the inverse binary of upper threshold with bitwise_and to remove above limit values from lower threshold.

//find range between high and low values of H
cv::cuda::threshold(mat_parts[0], mat_parts_low[0], hsv_low[0], MAX_UCHAR, cv::THRESH_BINARY);
cv::cuda::threshold(mat_parts[0], mat_parts_high[0],  hsv_high[0], MAX_UCHAR, cv::THRESH_BINARY_INV);
cv::cuda::bitwise_and(mat_parts_high[0], mat_parts_low[0], mat_parts[0]);

//find range between high and low values of S
cv::cuda::threshold(mat_parts[1], mat_parts_low[1], hsv_low[1], MAX_UCHAR, cv::THRESH_BINARY);
cv::cuda::threshold(mat_parts[1], mat_parts_high[1],  hsv_high[1], MAX_UCHAR, cv::THRESH_BINARY_INV);
cv::cuda::bitwise_and(mat_parts_high[1], mat_parts_low[1], mat_parts[1]);

//find range between high and low values of V
cv::cuda::threshold(mat_parts[2], mat_parts_low[2], hsv_low[2], MAX_UCHAR, cv::THRESH_BINARY);
cv::cuda::threshold(mat_parts[2], mat_parts_high[2],  hsv_high[2], MAX_UCHAR, cv::THRESH_BINARY_INV);
cv::cuda::bitwise_and(mat_parts_high[2], mat_parts_low[2], mat_parts[2]);

cv::cuda::GpuMat tmp1, final_result;

//bitwise AND all channels.
cv::cuda::bitwise_and(mat_parts[0], mat_parts[1], tmp3);
cv::cuda::bitwise_and(tmp3, tmp1);
cv::cuda::bitwise_and(tmp1, mat_parts[2], tmp4);
final_result);

cv::Mat img_final(final_result);