Image_Color - removed semibroken summ/difference operators.
Image_Diff now uses signed integer for computing differnce between ubyte3 components;
properly compare squared tolerance.
Image_Diff - dropped declaration of Image_ColorXXX24.
RGB color difference is now computed using Chebyshev distance instead of Euclidean distance
Image_PixMap - added methods RawValue()/ChangeRawValue() returning a pointer
to image where specified pixel data is defined.
};
-//! Addition operator
-template<typename ColorType_t>
-inline ColorType_t Image_ColorSumm3 (const ColorType_t& theA, const ColorType_t& theB)
-{
- ColorType_t aRes = {{typename ColorType_t::ComponentType_t (theA.v[0] + theB.v[0]),
- typename ColorType_t::ComponentType_t (theA.v[1] + theB.v[1]),
- typename ColorType_t::ComponentType_t (theA.v[2] + theB.v[2])}};
- return aRes;
-}
-
-inline Image_ColorRGB operator+ (const Image_ColorRGB& theA, const Image_ColorRGB& theB)
-{
- return Image_ColorSumm3 (theA, theB);
-}
-
-inline Image_ColorBGR operator+ (const Image_ColorBGR& theA, const Image_ColorBGR& theB)
-{
- return Image_ColorSumm3 (theA, theB);
-}
-
-inline Image_ColorRGBF operator+ (const Image_ColorRGBF& theA, const Image_ColorRGBF& theB)
-{
- return Image_ColorSumm3 (theA, theB);
-}
-
-inline Image_ColorBGRF operator+ (const Image_ColorBGRF& theA, const Image_ColorBGRF& theB)
-{
- return Image_ColorSumm3 (theA, theB);
-}
-
-template<typename ColorType_t>
-inline ColorType_t Image_ColorSumm4 (const ColorType_t& theA, const ColorType_t& theB)
-{
- ColorType_t aRes = {{typename ColorType_t::ComponentType_t (theA.v[0] + theB.v[0]),
- typename ColorType_t::ComponentType_t (theA.v[1] + theB.v[1]),
- typename ColorType_t::ComponentType_t (theA.v[2] + theB.v[2]),
- typename ColorType_t::ComponentType_t (theA.v[3] + theB.v[3])}};
- return aRes;
-}
-
-inline Image_ColorRGBA operator+ (const Image_ColorRGBA& theA, const Image_ColorRGBA& theB)
-{
- return Image_ColorSumm4 (theA, theB);
-}
-
-inline Image_ColorBGRA operator+ (const Image_ColorBGRA& theA, const Image_ColorBGRA& theB)
-{
- return Image_ColorSumm4 (theA, theB);
-}
-
-inline Image_ColorRGB32 operator+ (const Image_ColorRGB32& theA, const Image_ColorRGB32& theB)
-{
- return Image_ColorSumm4 (theA, theB);
-}
-
-inline Image_ColorBGR32 operator+ (const Image_ColorBGR32& theA, const Image_ColorBGR32& theB)
-{
- return Image_ColorSumm4 (theA, theB);
-}
-
-inline Image_ColorRGBAF operator+ (const Image_ColorRGBAF& theA, const Image_ColorRGBAF& theB)
-{
- return Image_ColorSumm4 (theA, theB);
-}
-
-inline Image_ColorBGRAF operator+ (const Image_ColorBGRAF& theA, const Image_ColorBGRAF& theB)
-{
- return Image_ColorSumm4 (theA, theB);
-}
-
-//! Subtraction operator
-template<typename ColorType_t>
-inline ColorType_t Image_ColorSub3 (const ColorType_t& theA, const ColorType_t& theB)
-{
- ColorType_t aRes = {{typename ColorType_t::ComponentType_t (theA.v[0] - theB.v[0]),
- typename ColorType_t::ComponentType_t (theA.v[1] - theB.v[1]),
- typename ColorType_t::ComponentType_t (theA.v[2] - theB.v[2])}};
- return aRes;
-}
-
-inline Image_ColorRGB operator- (const Image_ColorRGB& theA, const Image_ColorRGB& theB)
-{
- return Image_ColorSub3 (theA, theB);
-}
-
-inline Image_ColorBGR operator- (const Image_ColorBGR& theA, const Image_ColorBGR& theB)
-{
- return Image_ColorSub3 (theA, theB);
-}
-
-inline Image_ColorRGBF operator- (const Image_ColorRGBF& theA, const Image_ColorRGBF& theB)
-{
- return Image_ColorSub3 (theA, theB);
-}
-
-inline Image_ColorBGRF operator- (const Image_ColorBGRF& theA, const Image_ColorBGRF& theB)
-{
- return Image_ColorSub3 (theA, theB);
-}
-
-template<typename ColorType_t>
-inline ColorType_t Image_ColorSub4 (const ColorType_t& theA, const ColorType_t& theB)
-{
- ColorType_t aRes = {{typename ColorType_t::ComponentType_t (theA.v[0] - theB.v[0]),
- typename ColorType_t::ComponentType_t (theA.v[1] - theB.v[1]),
- typename ColorType_t::ComponentType_t (theA.v[2] - theB.v[2]),
- typename ColorType_t::ComponentType_t (theA.v[3] - theB.v[3])}};
- return aRes;
-}
-
-inline Image_ColorRGBA operator- (const Image_ColorRGBA& theA, const Image_ColorRGBA& theB)
-{
- return Image_ColorSub4 (theA, theB);
-}
-
-inline Image_ColorBGRA operator- (const Image_ColorBGRA& theA, const Image_ColorBGRA& theB)
-{
- return Image_ColorSub4 (theA, theB);
-}
-
-inline Image_ColorRGB32 operator- (const Image_ColorRGB32& theA, const Image_ColorRGB32& theB)
-{
- return Image_ColorSub4 (theA, theB);
-}
-
-inline Image_ColorBGR32 operator- (const Image_ColorBGR32& theA, const Image_ColorBGR32& theB)
-{
- return Image_ColorSub4 (theA, theB);
-}
-
-inline Image_ColorRGBAF operator- (const Image_ColorRGBAF& theA, const Image_ColorRGBAF& theB)
-{
- return Image_ColorSub4 (theA, theB);
-}
-
-inline Image_ColorBGRAF operator- (const Image_ColorBGRAF& theA, const Image_ColorBGRAF& theB)
-{
- return Image_ColorSub4 (theA, theB);
-}
-
#endif // _Image_Color_H__
namespace
{
- //! POD structure for packed RGB color value (3 bytes)
- struct Image_ColorXXX24
- {
- Standard_Byte v[3];
- typedef Standard_Byte ComponentType_t; //!< Component type
- };
-
- static Image_ColorXXX24 operator- (const Image_ColorXXX24& theA,
- const Image_ColorXXX24& theB)
- {
- return Image_ColorSub3 (theA, theB);
- }
-
- //! Dot squared for difference of two colors
- static Standard_Integer dotSquared (const Image_ColorXXX24& theColor)
- {
- // explicitly convert to integer
- const Standard_Integer r = theColor.v[0];
- const Standard_Integer g = theColor.v[1];
- const Standard_Integer b = theColor.v[2];
- return r * r + g * g + b * b;
- }
-
//! Number of neighbor pixels.
static const Standard_Size Image_Diff_NbOfNeighborPixels = 8;
case Image_Format_RGBA:
case Image_Format_BGRA:
{
- const Image_ColorXXX24& aColor = theData.Value<Image_ColorXXX24> (theY, theX);
- return aColor.v[0] == 0
- && aColor.v[1] == 0
- && aColor.v[2] == 0;
+ const Standard_Byte* aColor = theData.RawValue (theY, theX);
+ return aColor[0] == 0
+ && aColor[1] == 0
+ && aColor[2] == 0;
}
default:
{
case Image_Format_Alpha:
{
// Tolerance of comparison operation for color
- Standard_Integer aDiff = 255;
- const Standard_Real aMaxDiffColor = aDiff * aDiff;
- const Standard_Integer aDiffThreshold = Standard_Integer(aMaxDiffColor * myColorTolerance);
+ const Standard_Integer aDiffThreshold = Standard_Integer(255.0 * myColorTolerance);
for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
{
for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
{
- aDiff = Standard_Integer(myImageNew->Value<unsigned char> (aRow, aCol)) - Standard_Integer(myImageRef->Value<unsigned char> (aRow, aCol));
- if (aDiff * aDiff > aDiffThreshold)
+ const Standard_Integer aDiff = Standard_Integer(myImageNew->Value<unsigned char> (aRow, aCol)) - Standard_Integer(myImageRef->Value<unsigned char> (aRow, aCol));
+ if (Abs (aDiff) > aDiffThreshold)
{
myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
++aNbDiffColors;
{
// Tolerance of comparison operation for color
// Maximum difference between colors (white - black) = 100%
- Image_ColorXXX24 aDiff = {{255, 255, 255}};
- const Standard_Real aMaxDiffColor = dotSquared (aDiff);
- const Standard_Integer aDiffThreshold = Standard_Integer(aMaxDiffColor * myColorTolerance);
+ const Standard_Integer aDiffThreshold = Standard_Integer(255.0 * myColorTolerance);
// we don't care about RGB/BGR/RGBA/BGRA/RGB32/BGR32 differences
// because we just compute summ of r g b components
{
for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
{
- aDiff = myImageNew->Value<Image_ColorXXX24> (aRow, aCol) - myImageRef->Value<Image_ColorXXX24> (aRow, aCol);
- if (dotSquared (aDiff) > aDiffThreshold)
+ // compute Chebyshev distance between two colors
+ const Standard_Byte* aColorRef = myImageRef->RawValue (aRow, aCol);
+ const Standard_Byte* aColorNew = myImageNew->RawValue (aRow, aCol);
+ const int aDiff = NCollection_Vec3<int> (int(aColorRef[0]) - int(aColorNew[0]),
+ int(aColorRef[1]) - int(aColorNew[1]),
+ int(aColorRef[2]) - int(aColorNew[2])).cwiseAbs().maxComp();
+ if (aDiff > aDiffThreshold)
{
myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
++aNbDiffColors;
{
// Tolerance of comparison operation for color
// Maximum difference between colors (white - black) = 100%
- NCollection_Vec3<float> aDiff (1.0f, 1.0f, 1.0f);
- const Standard_Real aMaxDiffColor = aDiff.SquareModulus();
- const Standard_Integer aDiffThreshold = Standard_Integer(aMaxDiffColor * myColorTolerance);
+ const float aDiffThreshold = float(myColorTolerance);
for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
{
for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
{
+ // compute Chebyshev distance between two colors
const Quantity_ColorRGBA aPixel1Rgba = myImageRef->PixelColor (Standard_Integer(aCol), Standard_Integer(aRow));
const Quantity_ColorRGBA aPixel2Rgba = myImageNew->PixelColor (Standard_Integer(aCol), Standard_Integer(aRow));
const NCollection_Vec3<float>& aPixel1 = aPixel1Rgba.GetRGB();
const NCollection_Vec3<float>& aPixel2 = aPixel2Rgba.GetRGB();
- aDiff = aPixel2 - aPixel1;
- if (aDiff.SquareModulus() > aDiffThreshold)
+ const float aDiff = (aPixel2 - aPixel1).cwiseAbs().maxComp();
+ if (aDiff > aDiffThreshold)
{
myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
++aNbDiffColors;
}
}
- const Image_ColorXXX24 aWhite24 = {{255, 255, 255}};
const Quantity_ColorRGBA aWhiteRgba (1.0f, 1.0f, 1.0f, 1.0f);
// initialize black image for dump
{
for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
{
- theDiffImage.ChangeValue<Image_ColorXXX24> (UnpackY(aPixelIter.Value()), UnpackX(aPixelIter.Value())) = aWhite24;
+ memset (theDiffImage.ChangeRawValue (UnpackY(aPixelIter.Value()), UnpackX(aPixelIter.Value())), 255, 3);
}
break;
}
for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
{
Standard_Integer aDiffPixel (aPixelIter.Key());
- theDiffImage.ChangeValue<Image_ColorXXX24> (UnpackY(aDiffPixel), UnpackX(aDiffPixel)) = aWhite24;
+ memset (theDiffImage.ChangeValue<Standard_Byte*> (UnpackY(aDiffPixel), UnpackX(aDiffPixel)), 255, 3);
}
break;
}
return *reinterpret_cast<ColorType_t* >(myData.ChangeValue (theRow, theCol));
}
+ //! Access image pixel as raw data pointer.
+ //! This method does not perform any type checks - use on own risk (check Format() before)!
+ const Standard_Byte* RawValue (Standard_Size theRow,
+ Standard_Size theCol) const
+ {
+ return myData.Value (theRow, theCol);
+ }
+
+ //! Access image pixel as raw data pointer.
+ //! This method does not perform any type checks - use on own risk (check Format() before)!
+ Standard_Byte* ChangeRawValue (Standard_Size theRow,
+ Standard_Size theCol)
+ {
+ return myData.ChangeValue (theRow, theCol);
+ }
+
public:
Standard_DEPRECATED("This member is deprecated, use Image_Format enumeration instead")
--- /dev/null
+puts "============"
+puts "0029847: Visualization, Image_Diff - Tolerance is not effective for 24/32bit image formats"
+puts "============"
+puts ""
+
+pload VISUALIZATION
+vclear
+vinit View1
+vsetcolorbg 127 127 127
+vdump $imagedir/${casename}_127.png
+vsetcolorbg 130 130 130
+vdump $imagedir/${casename}_130.png
+set aNbDiff0 [diffimage $imagedir/${casename}_127.png $imagedir/${casename}_130.png $imagedir/${casename}_0.png -toleranceOfColor 0]
+set aNbDiff1 [diffimage $imagedir/${casename}_127.png $imagedir/${casename}_130.png $imagedir/${casename}_1.png -toleranceOfColor 0.1]
+set aNbDiff01 [diffimage $imagedir/${casename}_127.png $imagedir/${casename}_130.png $imagedir/${casename}_01.png -toleranceOfColor 0.01]
+if { $aNbDiff0 != 167281 } { puts "Error: difference with tolerance 0.0 is incorrect" }
+if { $aNbDiff1 != 0 } { puts "Error: difference with tolerance 0.1 is incorrect" }
+if { $aNbDiff01 != 167281 } { puts "Error: difference with tolerance 0.01 is incorrect" }