cvtColor: CV_RGB2HSV_FULL is inaccurate (Bug #938)
Description
Hi,
I've read the rgb to hsv conversion code, and found some inaccuracies especially with the _FULL mode that uses 0..255 as H range. After doing some tests, I found the biggest error at rgb=(251,2,255), giving an exact h value of 212.66, but computes to 208 by OpenCV.
Some more in-detail code analysis: In color.cpp, function cvtColor():
int hrange = depth CV_32F ? 360 : code CV_BGR2HSV || code CV_RGB2HSV ||
code CV_BGR2HLS || code == CV_RGB2HLS ? 180 : 255;
For _FULL, hrange should be 256 not 255. The actual range will be 0..hrange-1.
See also color.cpp, RGB2HSV_b::operator():
h += h < 0 ? hr : 0;
This should add 256 to negative values. (And could be replaced by h=uchar(h) in this case.)
int hr = hrange, hscale = hr == 180 ? 15 : 21;
...
h = (h * div_table[diff] * hscale + (1 << (hsv_shift + 6))) >> (7 + hsv_shift);
hscale is actually hrange*128/6/255, which evaluates to acceptable 15.05 for hrange=180, but 21.42 for hrange=256, which introduces serious rounding errors. This is the main source of h inaccuracy. Worst case error here is 5*diff*0.42/128, which can be up to +4.18 for the h component.
This can be avoided by using another division table
table[diff] = Round((hrange << shift)/(6.0*diff)), and
h = (h * table[diff] + (1 << (shift-1))) >> shift.
This will also be faster.
In color.cpp, RGB2HSV_b::operator():
s = diff * div_table[v] >> hsv_shift;
This should use rounding, eg. +(1<<(hsv_shift-1)) to avoid embarrassing rounding errors, like rgb=(0,0,9) having saturation 254 instead of 255.
Associated revisions
improved CV_RGBHSV_FULL accuracy (ticket #938)
Merge pull request #938 from pengx17:2.4_surf_sample
Merge remote-tracking branch 'origin/2.4' into merge-2.4
Merged pull requests:
#890 from caorong:patch-1
#893 from jet47:gpu-arm-fixes
#933 from pengx17:2.4_macfix_cont
#935 from pengx17:2.4_filter2d_fix
#936 from bitwangyaoyao:2.4_perf
#937 from bitwangyaoyao:2.4_fixPyrLK
#938 from pengx17:2.4_surf_sample
#939 from pengx17:2.4_getDevice
#940 from SpecLad:autolock
#941 from apavlenko:signed_char
#946 from bitwangyaoyao:2.4_samples2
#947 from jet47:fix-gpu-arm-build
#948 from jet47:cuda-5.5-support
#952 from SpecLad:jepg
#953 from jet47:fix-bug-3069
#955 from SpecLad:symlink
#957 from pengx17:2.4_fix_corner_detector
#959 from SpecLad:qt4-build
#960 from SpecLad:extra-modules
Conflicts:
modules/core/include/opencv2/core/core.hpp
modules/gpu/CMakeLists.txt
modules/gpu/include/opencv2/gpu/device/vec_math.hpp
modules/gpu/perf/perf_video.cpp
modules/gpuimgproc/src/cuda/hough.cu
modules/ocl/include/opencv2/ocl/ocl.hpp
modules/ocl/src/pyrlk.cpp
samples/gpu/driver_api_multi.cpp
samples/gpu/driver_api_stereo_multi.cpp
samples/ocl/surf_matcher.cpp
History
Updated by Vadim Pisarevsky almost 14 years ago
thanks! the proposed changes have been integrated into SVN trunk (r5324)
- Status changed from Open to Done
- (deleted custom field) set to fixed