Quantity_ColorRGBA - added method SetValues().
Image_PixMap::PixelColor() now returns Quantity_ColorRGBA instead of Quantity_Color.
Image_PixMap::SetPixelColor() now takes Quantity_ColorRGBA instead of NCollection_Vec4<float>.
Image_Diff has been improved to support Image_Format_Gray.
Image_Diff::SaveDiffImage() now saves image difference
in Image_Format_Gray format to reduce size of image file.
Image_Diff now uses TColStd_HPackedMapOfInteger instead of
TColStd_MapOfInteger with manual memory allocation.
# Conflicts:
# dox/dev_guides/upgrade/upgrade.md
# src/Graphic3d/Graphic3d_MarkerImage.cxx
# src/Image/Image_AlienPixMap.cxx
# src/Image/Image_PixMap.cxx
# src/Image/Image_PixMap.hxx
# src/ViewerTest/ViewerTest_ViewerCommands.cxx
{
for (Standard_Integer aColumn = 0; aColumn < aWidth; aColumn++)
{
- Quantity_Parameter anAlphaValue;
- Quantity_Color aColor = myImage->PixelColor (aColumn, aRow, anAlphaValue);
+ const Quantity_ColorRGBA aColor = myImage->PixelColor (aColumn, aRow);
Standard_Boolean aBitOn = Standard_False;
-
- if (myImage->Format() == Image_Format_Alpha)
- {
- aBitOn = anAlphaValue > theAlphaValue;
- }
- else if (myImage->Format() == Image_Format_Gray)
+ if (myImage->Format() == Image_Format_Gray)
{
- aBitOn = aColor.Red() > theAlphaValue;
+ aBitOn = aColor.GetRGB().Red() > theAlphaValue;
}
- else
+ else //if (myImage->Format() == Image_Format_Alpha)
{
- aBitOn = anAlphaValue > theAlphaValue;
+ aBitOn = aColor.Alpha() > theAlphaValue;
}
Standard_Integer anIndex = aNumOfBytesInRow * aRow + aColumn / 8;
myImageAlpha = new Image_PixMap();
myImageAlpha->InitZero (Image_Format_Alpha, myImage->Width(), myImage->Height());
myImageAlpha->SetTopDown (Standard_False);
- Quantity_Parameter anAlpha;
for (Standard_Size aRowIter = 0; aRowIter < myImage->Height(); aRowIter++)
{
Standard_Byte* anImageRow = myImageAlpha->ChangeRow (aRowIter);
for (Standard_Size aColumnIter = 0; aColumnIter < myImage->Width(); aColumnIter++)
{
- myImage->PixelColor ((Standard_Integer)aColumnIter, (Standard_Integer)aRowIter, anAlpha);
- anImageRow[aColumnIter] = Standard_Byte (255.0 * anAlpha);
+ const Quantity_ColorRGBA aColor = myImage->PixelColor ((Standard_Integer)aColumnIter, (Standard_Integer)aRowIter);
+ anImageRow[aColumnIter] = Standard_Byte (255.0 * aColor.Alpha());
}
}
}
fprintf (aFile, "# Image stored by OpenCASCADE framework in linear RGB colorspace\n");
// Write pixel data
- Quantity_Color aColor;
- Quantity_Parameter aDummy;
Standard_Byte aByte;
for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
{
for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
{
// extremely SLOW but universal (implemented for all supported pixel formats)
- aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow, aDummy);
- aByte = Standard_Byte(aColor.Red() * 255.0); fwrite (&aByte, 1, 1, aFile);
- aByte = Standard_Byte(aColor.Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
- aByte = Standard_Byte(aColor.Blue() * 255.0); fwrite (&aByte, 1, 1, aFile);
+ const Quantity_ColorRGBA aColor = PixelColor ((Standard_Integer )aCol, (Standard_Integer )aRow);
+ aByte = Standard_Byte(aColor.GetRGB().Red() * 255.0); fwrite (&aByte, 1, 1, aFile);
+ aByte = Standard_Byte(aColor.GetRGB().Green() * 255.0); fwrite (&aByte, 1, 1, aFile);
+ aByte = Standard_Byte(aColor.GetRGB().Blue() * 255.0); fwrite (&aByte, 1, 1, aFile);
}
}
// commercial license or contractual agreement.
#include <Image_Diff.hxx>
-#include <Image_AlienPixMap.hxx>
-#include <TColStd_MapIteratorOfMapOfInteger.hxx>
+#include <Image_AlienPixMap.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
#include <cstdlib>
-
IMPLEMENT_STANDARD_RTTIEXT(Image_Diff,Standard_Transient)
-//! POD structure for packed RGB color value (3 bytes)
-struct Image_ColorXXX24
-{
- Standard_Byte v[3];
- typedef Standard_Byte ComponentType_t; //!< Component type
- static Standard_Integer Length() { return 3; } //!< Returns the number of components
-};
-
-inline Image_ColorXXX24 operator- (const Image_ColorXXX24& theA,
- const Image_ColorXXX24& theB)
-{
- return Image_ColorSub3 (theA, theB);
-}
-
-//! Dot squared for difference of two colors
-inline 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;
-}
-
-//! @return true if pixel is black
-inline bool isBlack (const Image_ColorXXX24& theColor)
-{
- return theColor.v[0] == 0
- && theColor.v[1] == 0
- && theColor.v[2] == 0;
-}
-
-//! Converts a pixel position (row, column) to one integer value
-inline Standard_Size pixel2Int (const Standard_Size aRow,
- const Standard_Size aCol)
-{
- return aCol + (aRow << 15);
-}
-
-//! Converts an integer value to pixel coordinates (row, column)
-inline void int2Pixel (const Standard_Size theValue,
- Standard_Size& theRow,
- Standard_Size& theCol)
-{
- theRow = (theValue >> 15);
- theCol = theValue - (theRow << 15);
-}
-
namespace
{
- inline ptrdiff_t getAbs (const ptrdiff_t theValue)
+ //! POD structure for packed RGB color value (3 bytes)
+ struct Image_ColorXXX24
{
- return theValue >= 0 ? theValue : -theValue;
- }
+ Standard_Byte v[3];
+ typedef Standard_Byte ComponentType_t; //!< Component type
+ static Standard_Integer Length() { return 3; } //!< Returns the number of components
+ };
- static const Standard_Size NEIGHBOR_PIXELS_NB = 8;
- static struct
+ static Image_ColorXXX24 operator- (const Image_ColorXXX24& theA,
+ const Image_ColorXXX24& theB)
{
- Standard_Integer row_inc;
- Standard_Integer col_inc;
+ return Image_ColorSub3 (theA, theB);
+ }
- inline Standard_Size pixel2Int (const Standard_Size theRowCenter,
- const Standard_Size theColCenter) const
- {
- return ::pixel2Int (theRowCenter + Standard_Size(row_inc),
- theColCenter + Standard_Size(col_inc));
- }
+ //! 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;
+ }
- inline bool isBlack (const Image_PixMap& theData,
- const Standard_Size theRowCenter,
- const Standard_Size theColCenter) const
- {
- return ::isBlack (theData.Value<Image_ColorXXX24> (theRowCenter + Standard_Size(row_inc),
- theColCenter + Standard_Size(col_inc)));
- }
+ //! Number of neighbor pixels.
+ static const Standard_Size Image_Diff_NbOfNeighborPixels = 8;
- inline bool isValid (const Image_PixMap& theData,
- const Standard_Size theRowCenter,
- const Standard_Size theColCenter) const
- {
- const Standard_Size aRow = theRowCenter + Standard_Size(row_inc);
- const Standard_Size aCol = theColCenter + Standard_Size(col_inc);
- return aRow < theData.SizeX() // this unsigned math checks Standard_Size(-1) at-once
- && aCol < theData.SizeY();
- }
- }
- const NEIGHBOR_PIXELS[NEIGHBOR_PIXELS_NB] =
+ //! List of neighbor pixels (offsets).
+ static const int Image_Diff_NEIGHBOR_PIXELS[Image_Diff_NbOfNeighborPixels][2] =
{
- {-1, -1}, {-1, 0}, {-1, 1},
- { 0, -1}, { 0, 1},
- { 1, -1}, { 1, 0}, { 1, 1}
+ {-1, -1}, {0, -1}, {1, -1},
+ {-1, 0}, {1, 0},
+ {-1, 1}, {0, 1}, {1, 1}
};
- static bool isSupportedFormat (const Image_Format theFormat)
+ //! @return true if pixel is black
+ static bool isBlackPixel (const Image_PixMap& theData, Standard_Size theY, Standard_Size theX)
{
- return theFormat == Image_Format_RGB
- || theFormat == Image_Format_BGR
- || theFormat == Image_Format_RGB32
- || theFormat == Image_Format_BGR32
- || theFormat == Image_Format_RGBA
- || theFormat == Image_Format_BGRA;
+ switch (theData.Format())
+ {
+ case Image_Format_Gray:
+ case Image_Format_Alpha:
+ {
+ return theData.Value<unsigned char> (theY, theX) == 0;
+ }
+ case Image_Format_RGB:
+ case Image_Format_BGR:
+ case Image_Format_RGB32:
+ case Image_Format_BGR32:
+ 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;
+ }
+ default:
+ {
+ const Quantity_ColorRGBA aPixelRgba = theData.PixelColor ((int)theY, (int)theX);
+ const NCollection_Vec4<float>& aPixel = aPixelRgba;
+ return aPixel.r() == 0.0f
+ && aPixel.g() == 0.0f
+ && aPixel.b() == 0.0f;
+ }
+ }
}
-} // anonymous namespace
+}
// =======================================================================
// function : Image_Diff
|| theImageRef->SizeY() != theImageNew->SizeY()
|| theImageRef->Format() != theImageNew->Format())
{
-#ifdef OCCT_DEBUG
- std::cerr << "Images has different format or dimensions\n";
-#endif
- return Standard_False;
- }
- else if (!isSupportedFormat (theImageRef->Format()))
- {
-#ifdef OCCT_DEBUG
- std::cerr << "Images has unsupported pixel format\n";
-#endif
+ Message::DefaultMessenger()->Send ("Error: Images have different format or dimensions", Message_Fail);
return Standard_False;
}
else if (theImageRef->SizeX() >= 0xFFFF
|| theImageRef->SizeY() >= 0xFFFF)
{
-#ifdef OCCT_DEBUG
- std::cerr << "Image too large\n";
-#endif
+ Message::DefaultMessenger()->Send ("Error: Images are too large", Message_Fail);
return Standard_False;
}
myImageRef = theImageRef;
myImageNew = theImageNew;
-
if (theToBlackWhite)
{
- // Convert the images to white/black
- const Image_ColorXXX24 aWhite = {{255, 255, 255}};
- for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
- {
- for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
- {
- Image_ColorXXX24& aPixel1 = myImageRef->ChangeValue<Image_ColorXXX24> (aRow, aCol);
- if (!isBlack (aPixel1))
- {
- aPixel1 = aWhite;
- }
- Image_ColorXXX24& aPixel2 = myImageNew->ChangeValue<Image_ColorXXX24> (aRow, aCol);
- if (!isBlack (aPixel2))
- {
- aPixel2 = aWhite;
- }
- }
- }
+ Image_PixMap::ToBlackWhite (*myImageRef);
+ Image_PixMap::ToBlackWhite (*myImageNew);
}
-
return Standard_True;
}
-
// =======================================================================
// function : Init
// purpose :
if (!anImgRef->Load (theImgPathRef)
|| !anImgNew->Load (theImgPathNew))
{
-#ifdef OCCT_DEBUG
- std::cerr << "Failed to load image(s) file(s)\n";
-#endif
+ Message::DefaultMessenger()->Send ("Error: Failed to load image(s) file(s)", Message_Fail);
return Standard_False;
}
return Init (anImgRef, anImgNew, theToBlackWhite);
}
-// =======================================================================
-// function : SetColorTolerance
-// purpose :
-// =======================================================================
-void Image_Diff::SetColorTolerance (const Standard_Real theTolerance)
-{
- myColorTolerance = theTolerance;
-}
-
-// =======================================================================
-// function : ColorTolerance
-// purpose :
-// =======================================================================
-Standard_Real Image_Diff::ColorTolerance() const
-{
- return myColorTolerance;
-}
-
-// =======================================================================
-// function : SetBorderFilterOn
-// purpose :
-// =======================================================================
-void Image_Diff::SetBorderFilterOn (const Standard_Boolean theToIgnore)
-{
- myIsBorderFilterOn = theToIgnore;
-}
-
-// =======================================================================
-// function : IsBorderFilterOn
-// purpose :
-// =======================================================================
-Standard_Boolean Image_Diff::IsBorderFilterOn() const
-{
- return myIsBorderFilterOn;
-}
-
// =======================================================================
// function : Compare
// purpose :
return -1;
}
- // first check if images are exactly teh same
- if (! memcmp (myImageNew->Data(), myImageRef->Data(), myImageRef->SizeBytes()))
+ // first check if images are exactly the same
+ if (myImageNew->SizeBytes() == myImageRef->SizeBytes()
+ && memcmp (myImageNew->Data(), myImageRef->Data(), myImageRef->SizeBytes()) == 0)
{
return 0;
}
- // Tolerance of comparison operation for color
- // Maximum difference between colors (white - black) = 100%
- Image_ColorXXX24 aDiff = {{255, 255, 255}};
- const Standard_Integer aMaxDiffColor = dotSquared (aDiff);
- const Standard_Integer aDiffThreshold = Standard_Integer(Standard_Real(aMaxDiffColor) * myColorTolerance);
-
- // we don't care about RGB/BGR/RGBA/BGRA/RGB32/BGR32 differences
- // because we just compute summ of r g b components
-
- // compare colors of each pixel
- for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
+ switch (myImageRef->Format())
{
- for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
+ case Image_Format_Gray:
+ case Image_Format_Alpha:
{
- aDiff = myImageNew->Value<Image_ColorXXX24> (aRow, aCol) - myImageRef->Value<Image_ColorXXX24> (aRow, aCol);
- if (dotSquared (aDiff) > aDiffThreshold)
+ // Tolerance of comparison operation for color
+ Standard_Integer aDiff = 255;
+ const Standard_Real aMaxDiffColor = aDiff * aDiff;
+ const Standard_Integer aDiffThreshold = Standard_Integer(aMaxDiffColor * myColorTolerance);
+ for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
{
- const Standard_Size aValue = pixel2Int (aRow, aCol);
- myDiffPixels.Append (aValue);
- ++aNbDiffColors;
+ 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)
+ {
+ myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
+ ++aNbDiffColors;
+ }
+ }
}
+ break;
+ }
+ case Image_Format_RGB:
+ case Image_Format_BGR:
+ case Image_Format_RGB32:
+ case Image_Format_BGR32:
+ case Image_Format_RGBA:
+ case Image_Format_BGRA:
+ {
+ // 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);
+
+ // 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 aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
+ {
+ 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)
+ {
+ myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
+ ++aNbDiffColors;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ {
+ // 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);
+ for (Standard_Size aRow = 0; aRow < myImageRef->SizeY(); ++aRow)
+ {
+ for (Standard_Size aCol = 0; aCol < myImageRef->SizeX(); ++aCol)
+ {
+ 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)
+ {
+ myDiffPixels.Append (PackXY ((uint16_t)aCol, (uint16_t)aRow));
+ ++aNbDiffColors;
+ }
+ }
+ }
+ break;
}
}
// take into account a border effect
- if (myIsBorderFilterOn && myDiffPixels.Length() > 0)
+ if (myIsBorderFilterOn && !myDiffPixels.IsEmpty())
{
aNbDiffColors = ignoreBorderEffect();
}
if (theDiffImage.IsEmpty()
|| theDiffImage.SizeX() != myImageRef->SizeX()
- || theDiffImage.SizeY() != myImageRef->SizeY()
- || !isSupportedFormat (theDiffImage.Format()))
+ || theDiffImage.SizeY() != myImageRef->SizeY())
{
- if (!theDiffImage.InitTrash (Image_Format_RGB, myImageRef->SizeX(), myImageRef->SizeY()))
+ if (!theDiffImage.InitTrash (Image_Format_Gray, myImageRef->SizeX(), myImageRef->SizeY()))
{
return Standard_False;
}
}
- Standard_Size aRow, aCol;
- const Image_ColorXXX24 aWhite = {{255, 255, 255}};
+ const Image_ColorXXX24 aWhite24 = {{255, 255, 255}};
+ const Quantity_ColorRGBA aWhiteRgba (1.0f, 1.0f, 1.0f, 1.0f);
// initialize black image for dump
memset (theDiffImage.ChangeData(), 0, theDiffImage.SizeBytes());
return Standard_True;
}
- for (Standard_Integer aPixelId = 0; aPixelId < myDiffPixels.Length(); ++aPixelId)
+ switch (theDiffImage.Format())
{
- const Standard_Size aValue = myDiffPixels.Value (aPixelId);
- int2Pixel (aValue, aRow, aCol);
- theDiffImage.ChangeValue<Image_ColorXXX24> (aRow, aCol) = aWhite;
+ case Image_Format_Gray:
+ case Image_Format_Alpha:
+ {
+ for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
+ {
+ theDiffImage.ChangeValue<unsigned char> (UnpackY(aPixelIter.Value()), UnpackX(aPixelIter.Value())) = 255;
+ }
+ break;
+ }
+ case Image_Format_RGB:
+ case Image_Format_BGR:
+ case Image_Format_RGB32:
+ case Image_Format_BGR32:
+ case Image_Format_RGBA:
+ case Image_Format_BGRA:
+ {
+ for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
+ {
+ theDiffImage.ChangeValue<Image_ColorXXX24> (UnpackY(aPixelIter.Value()), UnpackX(aPixelIter.Value())) = aWhite24;
+ }
+ break;
+ }
+ default:
+ {
+ for (NCollection_Vector<Standard_Integer>::Iterator aPixelIter (myDiffPixels); aPixelIter.More(); aPixelIter.Next())
+ {
+ theDiffImage.SetPixelColor (UnpackX(aPixelIter.Value()), UnpackY(aPixelIter.Value()), aWhiteRgba);
+ }
+ break;
+ }
}
-
return Standard_True;
}
Standard_Integer aGroupId = 1;
- for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
+ for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
{
if (myLinearGroups.Contains (aGroupId))
{
continue; // skip linear groups
}
- const TColStd_MapOfInteger* aGroup = aGrIter.Value();
- for (TColStd_MapIteratorOfMapOfInteger aPixelIter(*aGroup);
- aPixelIter.More(); aPixelIter.Next())
+ const Handle(TColStd_HPackedMapOfInteger)& aGroup = aGrIter.Value();
+ switch (theDiffImage.Format())
{
- int2Pixel (aPixelIter.Key(), aRow, aCol);
- theDiffImage.ChangeValue<Image_ColorXXX24> (aRow, aCol) = aWhite;
+ case Image_Format_Gray:
+ case Image_Format_Alpha:
+ {
+ for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
+ {
+ Standard_Integer aDiffPixel (aPixelIter.Key());
+ theDiffImage.ChangeValue<unsigned char> (UnpackY(aDiffPixel), UnpackX(aDiffPixel)) = 255;
+ }
+ break;
+ }
+ case Image_Format_RGB:
+ case Image_Format_BGR:
+ case Image_Format_RGB32:
+ case Image_Format_BGR32:
+ case Image_Format_RGBA:
+ case Image_Format_BGRA:
+ {
+ for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
+ {
+ Standard_Integer aDiffPixel (aPixelIter.Key());
+ theDiffImage.ChangeValue<Image_ColorXXX24> (UnpackY(aDiffPixel), UnpackX(aDiffPixel)) = aWhite24;
+ }
+ break;
+ }
+ default:
+ {
+ for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
+ {
+ Standard_Integer aDiffPixel (aPixelIter.Key());
+ theDiffImage.SetPixelColor (UnpackX(aDiffPixel), UnpackY(aDiffPixel), aWhiteRgba);
+ }
+ break;
+ }
}
}
}
Image_AlienPixMap aDiff;
- if (!aDiff.InitTrash (Image_Format_RGB, myImageRef->SizeX(), myImageRef->SizeY())
+ if (!aDiff.InitTrash (Image_Format_Gray, myImageRef->SizeX(), myImageRef->SizeY())
|| !SaveDiffImage (aDiff))
{
return Standard_False;
// Find a different area (a set of close to each other pixels which colors differ in both images).
// It filters alone pixels with different color.
- Standard_Size aRow1 = 0, aCol1 = 0, aRow2, aCol2;
- Standard_Integer aLen1 = (myDiffPixels.Length() > 0) ? (myDiffPixels.Length() - 1) : 0;
+ const Standard_Integer aLen1 = !myDiffPixels.IsEmpty() ? (myDiffPixels.Length() - 1) : 0;
for (Standard_Integer aPixelId1 = 0; aPixelId1 < aLen1; ++aPixelId1)
{
- const Standard_Size aValue1 = myDiffPixels.Value (aPixelId1);
- int2Pixel (aValue1, aRow1, aCol1);
+ Standard_Integer aValue1 = myDiffPixels.Value (aPixelId1);
// Check other pixels in the list looking for a neighbour of this one
for (Standard_Integer aPixelId2 = aPixelId1 + 1; aPixelId2 < myDiffPixels.Length(); ++aPixelId2)
{
- const Standard_Size aValue2 = myDiffPixels.Value (aPixelId2);
- int2Pixel (aValue2, aRow2, aCol2);
- if (getAbs (ptrdiff_t (aCol1 - aCol2)) <= 1 &&
- getAbs (ptrdiff_t (aRow1 - aRow2)) <= 1)
+ Standard_Integer aValue2 = myDiffPixels.Value (aPixelId2);
+ if (Abs (Standard_Integer(UnpackX(aValue1)) - Standard_Integer(UnpackX(aValue2))) <= 1
+ && Abs (Standard_Integer(UnpackY(aValue1)) - Standard_Integer(UnpackY(aValue2))) <= 1)
{
// A neighbour is found. Create a new group and add both pixels.
if (myGroupsOfDiffPixels.IsEmpty())
{
- TColStd_MapOfInteger* aGroup = new TColStd_MapOfInteger();
- aGroup->Add ((Standard_Integer)aValue1);
- aGroup->Add ((Standard_Integer)aValue2);
+ Handle(TColStd_HPackedMapOfInteger) aGroup = new TColStd_HPackedMapOfInteger();
+ aGroup->ChangeMap().Add (aValue1);
+ aGroup->ChangeMap().Add (aValue2);
myGroupsOfDiffPixels.Append (aGroup);
}
else
{
// Find a group the pixels belong to.
Standard_Boolean isFound = Standard_False;
- for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next())
+ for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next())
{
- TColStd_MapOfInteger*& aGroup = aGrIter.ChangeValue();
- if (aGroup->Contains ((Standard_Integer)aValue1))
+ const Handle(TColStd_HPackedMapOfInteger)& aGroup = aGrIter.ChangeValue();
+ if (aGroup->Map().Contains (aValue1))
{
- aGroup->Add ((Standard_Integer)aValue2);
+ aGroup->ChangeMap().Add (aValue2);
isFound = Standard_True;
break;
}
if (!isFound)
{
// Create a new group
- TColStd_MapOfInteger* aGroup = new TColStd_MapOfInteger();
- aGroup->Add ((Standard_Integer)aValue1);
- aGroup->Add ((Standard_Integer)aValue2);
+ Handle(TColStd_HPackedMapOfInteger) aGroup = new TColStd_HPackedMapOfInteger();
+ aGroup->ChangeMap().Add (aValue1);
+ aGroup->ChangeMap().Add (aValue2);
myGroupsOfDiffPixels.Append (aGroup);
}
}
// filter linear groups which represent border of a solid shape
Standard_Integer aGroupId = 1;
- for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
+ for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
{
Standard_Integer aNeighboursNb = 0;
Standard_Boolean isLine = Standard_True;
- const TColStd_MapOfInteger* aGroup = aGrIter.Value();
- for (TColStd_MapIteratorOfMapOfInteger aPixelIter (*aGroup); aPixelIter.More(); aPixelIter.Next())
+ const Handle(TColStd_HPackedMapOfInteger)& aGroup = aGrIter.Value();
+ if (aGroup->Map().IsEmpty())
{
- int2Pixel (aPixelIter.Key(), aRow1, aCol1);
+ continue;
+ }
+
+ Standard_Integer aDiffPixel = 0;
+ for (TColStd_MapIteratorOfPackedMapOfInteger aPixelIter (aGroup->Map()); aPixelIter.More(); aPixelIter.Next())
+ {
+ aDiffPixel = aPixelIter.Key();
aNeighboursNb = 0;
// pixels of a line have only 1 or 2 neighbour pixels inside the same group
// check all neighbour pixels on presence in the group
- for (Standard_Size aNgbrIter = 0; aNgbrIter < NEIGHBOR_PIXELS_NB; ++aNgbrIter)
+ for (Standard_Size aNgbrIter = 0; aNgbrIter < Image_Diff_NbOfNeighborPixels; ++aNgbrIter)
{
- if (NEIGHBOR_PIXELS[aNgbrIter].isValid (*myImageRef, aRow1, aCol1)
- && aGroup->Contains ((Standard_Integer)NEIGHBOR_PIXELS[aNgbrIter].pixel2Int (aRow1, aCol1)))
+ Standard_Integer anX = UnpackX(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][0];
+ Standard_Integer anY = UnpackY(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][1];
+ if (Standard_Size(anX) < myImageRef->SizeX() // this unsigned math checks Standard_Size(-1) at-once
+ && Standard_Size(anY) < myImageRef->SizeY()
+ && aGroup->Map().Contains (PackXY((uint16_t)anX, (uint16_t)anY)))
{
++aNeighboursNb;
}
isLine = Standard_False;
break;
}
- } // for pixels inside group...
+ }
if (isLine)
{
// If the pixel has greater than 1 not black neighbour pixel, it is a border of a shape.
// Otherwise, it may be a topological edge, for example.
aNeighboursNb = 0;
- for (Standard_Size aNgbrIter = 0; aNgbrIter < NEIGHBOR_PIXELS_NB; ++aNgbrIter)
+ for (Standard_Size aNgbrIter = 0; aNgbrIter < Image_Diff_NbOfNeighborPixels; ++aNgbrIter)
{
- if ( NEIGHBOR_PIXELS[aNgbrIter].isValid (*myImageRef, aRow1, aCol1)
- && !NEIGHBOR_PIXELS[aNgbrIter].isBlack (*myImageRef, aRow1, aCol1))
+ Standard_Integer anX = UnpackX(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][0];
+ Standard_Integer anY = UnpackY(aDiffPixel) + Image_Diff_NEIGHBOR_PIXELS[aNgbrIter][1];
+ if (Standard_Size(anX) < myImageRef->SizeX() // this unsigned math checks Standard_Size(-1) at-once
+ && Standard_Size(anY) < myImageRef->SizeY()
+ && !isBlackPixel (*myImageRef, Standard_Size(anY), Standard_Size(anX)))
{
++aNeighboursNb;
}
myLinearGroups.Add (aGroupId);
}
}
- } // for groups...
+ }
// number of different groups of pixels (except linear groups)
Standard_Integer aNbDiffColors = 0;
aGroupId = 1;
- for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
+ for (NCollection_List<Handle(TColStd_HPackedMapOfInteger)>::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next(), ++aGroupId)
{
if (!myLinearGroups.Contains (aGroupId))
+ {
++aNbDiffColors;
+ }
}
return aNbDiffColors;
// =======================================================================
void Image_Diff::releaseGroupsOfDiffPixels()
{
- for (ListOfMapOfInteger::Iterator aGrIter (myGroupsOfDiffPixels); aGrIter.More(); aGrIter.Next())
- {
- TColStd_MapOfInteger*& aGroup = aGrIter.ChangeValue();
- delete aGroup;
- }
myGroupsOfDiffPixels.Clear();
myLinearGroups.Clear();
}
#include <Image_PixMap.hxx>
#include <TCollection_AsciiString.hxx>
-#include <TColStd_MapOfInteger.hxx>
+#include <TColStd_HPackedMapOfInteger.hxx>
#include <NCollection_List.hxx>
#include <NCollection_Vector.hxx>
//! Color tolerance for equality check. Should be within range 0..1:
//! Corresponds to a difference between white and black colors (maximum difference).
//! By default, the tolerance is equal to 0 thus equality check will return false for any different colors.
- Standard_EXPORT void SetColorTolerance (const Standard_Real theTolerance);
+ void SetColorTolerance (const Standard_Real theTolerance) { myColorTolerance = theTolerance; }
//! Color tolerance for equality check.
- Standard_EXPORT Standard_Real ColorTolerance() const;
+ Standard_Real ColorTolerance() const { return myColorTolerance; }
//! Sets taking into account (ignoring) a "border effect" on comparison of images.
//! The border effect is caused by a border of shaded shapes in the viewer 3d.
//! Therefore, they deflect light differently according to implementation of a video card driver.
//! This flag allows to detect such a "border" area and skip it from comparison of images.
//! Filter turned OFF by default.
- Standard_EXPORT void SetBorderFilterOn (const Standard_Boolean theToIgnore);
+ void SetBorderFilterOn (const Standard_Boolean theToIgnore) { myIsBorderFilterOn = theToIgnore; }
//! Returns a flag of taking into account (ignoring) a border effect in comparison of images.
- Standard_EXPORT Standard_Boolean IsBorderFilterOn() const;
+ Standard_Boolean IsBorderFilterOn() const { return myIsBorderFilterOn; }
//! Compares two images. It returns a number of different pixels (or groups of pixels).
//! It returns -1 if algorithm not initialized before.
protected:
- typedef NCollection_List<TColStd_MapOfInteger* > ListOfMapOfInteger;
+ //! Map two pixel coordinates to 32-bit integer
+ static Standard_Integer PackXY (uint16_t theX, uint16_t theY)
+ {
+ return Standard_Integer((unsigned int)theY |
+ ((unsigned int)theX << 16));
+ }
+
+ //! Get pixel X coordinate from 32-bit packed integer
+ static uint16_t UnpackX (Standard_Integer theXY)
+ {
+ return (uint16_t)(((unsigned int)theXY & 0xffff0000) >> 16);
+ }
+
+ //! Get pixel Y coordinate from 32-bit packed integer
+ static uint16_t UnpackY (Standard_Integer theXY)
+ {
+ return (uint16_t)((unsigned int)theXY & 0xffff);
+ }
+
+protected:
Handle(Image_PixMap) myImageRef; //!< reference image to compare (from)
Handle(Image_PixMap) myImageNew; //!< new image to compare (to)
Standard_Real myColorTolerance; //!< tolerance for equality check (0..1, 0 - any not equal, 1 - opposite colors)
+
Standard_Boolean myIsBorderFilterOn; //!< perform algorithm with border effect filter
- ListOfMapOfInteger myGroupsOfDiffPixels;
- NCollection_Vector<Standard_Size> myDiffPixels; //!< different pixels (position packed into integer)
- TColStd_MapOfInteger myLinearGroups;
+
+ //! coordinates of different pixels, packed in one int using 16-bit integers to save memory
+ NCollection_Vector<Standard_Integer> myDiffPixels;
+ TColStd_PackedMapOfInteger myLinearGroups;
+ NCollection_List<Handle(TColStd_HPackedMapOfInteger)>
+ myGroupsOfDiffPixels;
public:
// function : PixelColor
// purpose :
// =======================================================================
-Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX,
- const Standard_Integer theY,
- Quantity_Parameter& theAlpha) const
+Quantity_ColorRGBA Image_PixMap::PixelColor (const Standard_Integer theX,
+ const Standard_Integer theY) const
{
if (IsEmpty()
|| theX < 0 || (Standard_Size )theX >= SizeX()
|| theY < 0 || (Standard_Size )theY >= SizeY())
{
- theAlpha = 0.0; // transparent
- return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 0.0f); // transparent
}
switch (myImgFormat)
case Image_Format_GrayF:
{
const Standard_ShortReal& aPixel = Value<Standard_ShortReal> (theY, theX);
- theAlpha = 1.0; // opaque
- return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel)),
- Quantity_Parameter (Standard_Real (aPixel)),
- Quantity_Parameter (Standard_Real (aPixel)),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel, aPixel, aPixel, 1.0f)); // opaque
}
case Image_Format_AlphaF:
{
const Standard_ShortReal& aPixel = Value<Standard_ShortReal> (theY, theX);
- theAlpha = aPixel;
- return Quantity_Color (1.0, 1.0, 1.0, Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (NCollection_Vec4<float> (1.0f, 1.0f, 1.0f, aPixel));
}
case Image_Format_RGBAF:
{
const Image_ColorRGBAF& aPixel = Value<Image_ColorRGBAF> (theY, theX);
- theAlpha = aPixel.a();
- return Quantity_Color (Quantity_Parameter (aPixel.r()),
- Quantity_Parameter (aPixel.g()),
- Quantity_Parameter (aPixel.b()),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), aPixel.a()));
}
case Image_Format_BGRAF:
{
const Image_ColorBGRAF& aPixel = Value<Image_ColorBGRAF> (theY, theX);
- theAlpha = aPixel.a();
- return Quantity_Color (Quantity_Parameter (aPixel.r()),
- Quantity_Parameter (aPixel.g()),
- Quantity_Parameter (aPixel.b()),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), aPixel.a()));
}
case Image_Format_RGBF:
{
const Image_ColorRGBF& aPixel = Value<Image_ColorRGBF> (theY, theX);
- theAlpha = 1.0; // opaque
- return Quantity_Color (Quantity_Parameter (aPixel.r()),
- Quantity_Parameter (aPixel.g()),
- Quantity_Parameter (aPixel.b()),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), 1.0f)); // opaque
}
case Image_Format_BGRF:
{
const Image_ColorBGRF& aPixel = Value<Image_ColorBGRF> (theY, theX);
- theAlpha = 1.0; // opaque
- return Quantity_Color (Quantity_Parameter (aPixel.r()),
- Quantity_Parameter (aPixel.g()),
- Quantity_Parameter (aPixel.b()),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), 1.0f)); // opaque
}
case Image_Format_RGBA:
{
const Image_ColorRGBA& aPixel = Value<Image_ColorRGBA> (theY, theX);
- theAlpha = Standard_Real (aPixel.a()) / 255.0;
- return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, float(aPixel.a()) / 255.0f);
}
case Image_Format_BGRA:
{
const Image_ColorBGRA& aPixel = Value<Image_ColorBGRA> (theY, theX);
- theAlpha = Standard_Real (aPixel.a()) / 255.0;
- return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, float(aPixel.a()) / 255.0f);
}
case Image_Format_RGB32:
{
const Image_ColorRGB32& aPixel = Value<Image_ColorRGB32> (theY, theX);
- theAlpha = 1.0; // opaque
- return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
}
case Image_Format_BGR32:
{
const Image_ColorBGR32& aPixel = Value<Image_ColorBGR32> (theY, theX);
- theAlpha = 1.0; // opaque
- return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
}
case Image_Format_RGB:
{
const Image_ColorRGB& aPixel = Value<Image_ColorRGB> (theY, theX);
- theAlpha = 1.0; // opaque
- return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
}
case Image_Format_BGR:
{
const Image_ColorBGR& aPixel = Value<Image_ColorBGR> (theY, theX);
- theAlpha = 1.0; // opaque
- return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel.r()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.g()) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel.b()) / 255.0),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (float(aPixel.r()) / 255.0f, float(aPixel.g()) / 255.0f, float(aPixel.b()) / 255.0f, 1.0f); // opaque
}
case Image_Format_Gray:
{
const Standard_Byte& aPixel = Value<Standard_Byte> (theY, theX);
- theAlpha = 1.0; // opaque
- return Quantity_Color (Quantity_Parameter (Standard_Real (aPixel) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel) / 255.0),
- Quantity_Parameter (Standard_Real (aPixel) / 255.0),
- Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (float(aPixel) / 255.0f, float(aPixel) / 255.0f, float(aPixel) / 255.0f, 1.0f); // opaque
}
case Image_Format_Alpha:
{
const Standard_Byte& aPixel = Value<Standard_Byte> (theY, theX);
- theAlpha = Standard_Real (aPixel) / 255.0;
- return Quantity_Color (1.0, 1.0, 1.0, Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (1.0f, 1.0f, 1.0f, float(aPixel) / 255.0f);
}
case Image_Format_UNKNOWN:
{
}
// unsupported image type
- theAlpha = 0.0; // transparent
- return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB);
+ return Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 0.0f); // transparent
}
// =======================================================================
// =======================================================================
void Image_PixMap::SetPixelColor (const Standard_Integer theX,
const Standard_Integer theY,
- const NCollection_Vec4<float>& theColor)
+ const Quantity_ColorRGBA& theColor)
{
if (IsEmpty()
|| theX < 0 || Standard_Size(theX) >= SizeX()
return;
}
+ const NCollection_Vec4<float>& aColor = theColor;
switch (myImgFormat)
{
case Image_Format_GrayF:
{
- ChangeValue<Standard_ShortReal> (theY, theX) = theColor.r();
+ ChangeValue<Standard_ShortReal> (theY, theX) = aColor.r();
return;
}
case Image_Format_AlphaF:
{
- ChangeValue<Standard_ShortReal> (theY, theX) = theColor.a();
+ ChangeValue<Standard_ShortReal> (theY, theX) = aColor.a();
return;
}
case Image_Format_RGBAF:
{
Image_ColorRGBAF& aPixel = ChangeValue<Image_ColorRGBAF> (theY, theX);
- aPixel.r() = theColor.r();
- aPixel.g() = theColor.g();
- aPixel.b() = theColor.b();
- aPixel.a() = theColor.a();
+ aPixel.r() = aColor.r();
+ aPixel.g() = aColor.g();
+ aPixel.b() = aColor.b();
+ aPixel.a() = aColor.a();
return;
}
case Image_Format_BGRAF:
{
Image_ColorBGRAF& aPixel = ChangeValue<Image_ColorBGRAF> (theY, theX);
- aPixel.r() = theColor.r();
- aPixel.g() = theColor.g();
- aPixel.b() = theColor.b();
- aPixel.a() = theColor.a();
+ aPixel.r() = aColor.r();
+ aPixel.g() = aColor.g();
+ aPixel.b() = aColor.b();
+ aPixel.a() = aColor.a();
return;
}
case Image_Format_RGBF:
{
Image_ColorRGBF& aPixel = ChangeValue<Image_ColorRGBF> (theY, theX);
- aPixel.r() = theColor.r();
- aPixel.g() = theColor.g();
- aPixel.b() = theColor.b();
+ aPixel.r() = aColor.r();
+ aPixel.g() = aColor.g();
+ aPixel.b() = aColor.b();
return;
}
case Image_Format_BGRF:
{
Image_ColorBGRF& aPixel = ChangeValue<Image_ColorBGRF> (theY, theX);
- aPixel.r() = theColor.r();
- aPixel.g() = theColor.g();
- aPixel.b() = theColor.b();
+ aPixel.r() = aColor.r();
+ aPixel.g() = aColor.g();
+ aPixel.b() = aColor.b();
return;
}
case Image_Format_RGBA:
{
Image_ColorRGBA& aPixel = ChangeValue<Image_ColorRGBA> (theY, theX);
- aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
- aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
- aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
- aPixel.a() = Standard_Byte(theColor.a() * 255.0f);
+ aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+ aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+ aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
+ aPixel.a() = Standard_Byte(aColor.a() * 255.0f);
return;
}
case Image_Format_BGRA:
{
Image_ColorBGRA& aPixel = ChangeValue<Image_ColorBGRA> (theY, theX);
- aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
- aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
- aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
- aPixel.a() = Standard_Byte(theColor.a() * 255.0f);
+ aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+ aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+ aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
+ aPixel.a() = Standard_Byte(aColor.a() * 255.0f);
return;
}
case Image_Format_RGB32:
{
Image_ColorRGB32& aPixel = ChangeValue<Image_ColorRGB32> (theY, theX);
- aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
- aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
- aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+ aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+ aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+ aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
aPixel.a_() = 255;
return;
}
case Image_Format_BGR32:
{
Image_ColorBGR32& aPixel = ChangeValue<Image_ColorBGR32> (theY, theX);
- aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
- aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
- aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+ aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+ aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+ aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
aPixel.a_() = 255;
return;
}
case Image_Format_RGB:
{
Image_ColorRGB& aPixel = ChangeValue<Image_ColorRGB> (theY, theX);
- aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
- aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
- aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+ aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+ aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+ aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
return;
}
case Image_Format_BGR:
{
Image_ColorBGR& aPixel = ChangeValue<Image_ColorBGR> (theY, theX);
- aPixel.r() = Standard_Byte(theColor.r() * 255.0f);
- aPixel.g() = Standard_Byte(theColor.g() * 255.0f);
- aPixel.b() = Standard_Byte(theColor.b() * 255.0f);
+ aPixel.r() = Standard_Byte(aColor.r() * 255.0f);
+ aPixel.g() = Standard_Byte(aColor.g() * 255.0f);
+ aPixel.b() = Standard_Byte(aColor.b() * 255.0f);
return;
}
case Image_Format_Gray:
{
- ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(theColor.r() * 255.0f);
+ ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(aColor.r() * 255.0f);
return;
}
case Image_Format_Alpha:
{
- ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(theColor.a() * 255.0f);
+ ChangeValue<Standard_Byte> (theY, theX) = Standard_Byte(aColor.a() * 255.0f);
return;
}
case Image_Format_UNKNOWN:
default: return false;
}
}
+
+// =======================================================================
+// function : ToBlackWhite
+// purpose :
+// =======================================================================
+void Image_PixMap::ToBlackWhite (Image_PixMap& theImage)
+{
+ switch (theImage.Format())
+ {
+ case Image_Format_Gray:
+ case Image_Format_Alpha:
+ {
+ for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+ {
+ for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
+ {
+ unsigned char& aPixel = theImage.ChangeValue<unsigned char> (aRow, aCol);
+ if (aPixel != 0)
+ {
+ aPixel = 255;
+ }
+ }
+ }
+ break;
+ }
+ case Image_Format_RGB:
+ case Image_Format_BGR:
+ case Image_Format_RGB32:
+ case Image_Format_BGR32:
+ case Image_Format_RGBA:
+ case Image_Format_BGRA:
+ {
+ const NCollection_Vec3<unsigned char> aWhite24 (255, 255, 255);
+ for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+ {
+ for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
+ {
+ NCollection_Vec3<unsigned char>& aPixel = theImage.ChangeValue< NCollection_Vec3<unsigned char> > (aRow, aCol);
+ if (aPixel[0] != 0
+ || aPixel[1] != 0
+ || aPixel[2] != 0)
+ {
+ aPixel = aWhite24;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ {
+ const Quantity_ColorRGBA aWhiteRgba (1.0f, 1.0f, 1.0f, 1.0f);
+ for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+ {
+ for (Standard_Size aCol = 0; aCol < theImage.SizeX(); ++aCol)
+ {
+ const Quantity_ColorRGBA aPixelRgba = theImage.PixelColor (Standard_Integer(aCol), Standard_Integer(aRow));
+ const NCollection_Vec4<float>& aPixel = aPixelRgba;
+ if (aPixel[0] != 0.0f
+ || aPixel[1] != 0.0f
+ || aPixel[2] != 0.0f)
+ {
+ theImage.SetPixelColor (int(aCol), int(aRow), aWhiteRgba);
+ }
+ }
+ }
+ break;
+ }
+ }
+}
//! - Image_Format_RGBAF / Image_Format_BGRAF
Standard_EXPORT static bool SwapRgbaBgra (Image_PixMap& theImage);
+ //! Convert image to Black/White.
+ Standard_EXPORT static void ToBlackWhite (Image_PixMap& theImage);
+
public: // high-level API
Image_Format Format() const { return myImgFormat; }
//! @param theX column index from left
//! @param theY row index from top
//! @return the pixel color
- inline Quantity_Color PixelColor (const Standard_Integer theX,
- const Standard_Integer theY) const
- {
- Quantity_Parameter aDummy;
- return PixelColor (theX, theY, aDummy);
- }
-
- //! Returns the pixel color. This function is relatively slow.
- //! theAlpha argument is set to color intensity (0 - transparent, 1 - opaque)
- //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
- Standard_EXPORT Quantity_Color PixelColor (const Standard_Integer theX,
- const Standard_Integer theY,
- Quantity_Parameter& theAlpha) const;
-
- //! Sets the pixel color. This function is relatively slow.
- //! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
- void SetPixelColor (const Standard_Integer theX,
- const Standard_Integer theY,
- const Quantity_ColorRGBA& theColor)
- {
- const NCollection_Vec4<float> aColor = theColor;
- SetPixelColor (theX, theY, aColor);
- }
+ Standard_EXPORT Quantity_ColorRGBA PixelColor (const Standard_Integer theX,
+ const Standard_Integer theY) const;
//! Sets the pixel color. This function is relatively slow.
//! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
- void SetPixelColor(const Standard_Integer theX,
- const Standard_Integer theY,
- const Quantity_Color& theColor)
+ void SetPixelColor (const Standard_Integer theX,
+ const Standard_Integer theY,
+ const Quantity_Color& theColor)
{
- const NCollection_Vec3<float> aColor = theColor;
- SetPixelColor (theX, theY, NCollection_Vec4<float> (aColor, 1.0f));
+ SetPixelColor (theX, theY, Quantity_ColorRGBA (theColor, 1.0f));
}
//! Sets the pixel color. This function is relatively slow.
//! Beware that this method takes coordinates in opposite order in contrast to ::Value() and ::ChangeValue().
Standard_EXPORT void SetPixelColor (const Standard_Integer theX,
const Standard_Integer theY,
- const NCollection_Vec4<float>& theColor);
+ const Quantity_ColorRGBA& theColor);
//! Initialize image plane as wrapper over alien data.
//! Data will not be copied! Notice that caller should ensure
v[1] = theY;
}
+ //! Assign new values to the vector.
+ void SetValues (const Element_t theX,
+ const Element_t theY)
+ {
+ v[0] = theX;
+ v[1] = theY;
+ }
+
//! Alias to 1st component as X coordinate in XY.
Element_t x() const { return v[0]; }
v[2] = Element_t(0);
}
+ //! Assign new values to the vector.
+ void SetValues (const Element_t theX,
+ const Element_t theY,
+ const Element_t theZ)
+ {
+ v[0] = theX;
+ v[1] = theY;
+ v[2] = theZ;
+ }
+
//! Alias to 1st component as X coordinate in XYZ.
Element_t x() const { return v[0]; }
v[3] = theAlpha;
}
+ //! Assign new values to the vector.
+ void SetValues (const Element_t theX,
+ const Element_t theY,
+ const Element_t theZ,
+ const Element_t theW)
+ {
+ v[0] = theX;
+ v[1] = theY;
+ v[2] = theZ;
+ v[3] = theW;
+ }
+
//! Alias to 1st component as X coordinate in XYZW.
Element_t x() const { return v[0]; }
Quantity_ColorRGBA() : myAlpha (1.0f) {}
//! Creates the color with specified RGB value.
- explicit Quantity_ColorRGBA (const Quantity_Color& theRgb) : myRgb (theRgb), myAlpha (1.0f) {}
+ explicit Quantity_ColorRGBA (const Quantity_Color& theRgb)
+ : myRgb (theRgb), myAlpha (1.0f)
+ {}
+
+ //! Creates the color with specified RGBA values.
+ Quantity_ColorRGBA (const Quantity_Color& theRgb, float theAlpha)
+ : myRgb (theRgb), myAlpha (theAlpha)
+ {}
//! Creates the color from RGBA vector.
- explicit Quantity_ColorRGBA (const NCollection_Vec4<float>& theRgba) : myRgb (theRgba.rgb()), myAlpha (theRgba.a()) {}
+ explicit Quantity_ColorRGBA (const NCollection_Vec4<float>& theRgba)
+ : myRgb (theRgba.rgb()), myAlpha (theRgba.a())
+ {}
+
+ //! Creates the color from RGBA values.
+ Quantity_ColorRGBA (float theRed, float theGreen, float theBlue, float theAlpha)
+ : myRgb (theRed, theGreen, theBlue, Quantity_TOC_RGB),
+ myAlpha (theAlpha)
+ {}
+
+ //! Assign new values to the color.
+ void SetValues (float theRed, float theGreen, float theBlue, float theAlpha)
+ {
+ myRgb.SetValues (theRed, theGreen, theBlue, Quantity_TOC_RGB);
+ myAlpha = theAlpha;
+ }
//! Return RGB color value.
const Quantity_Color& GetRGB() const { return myRgb; }
private:
- static void __testSize3() { Standard_STATIC_ASSERT (sizeof(float) * 3 == sizeof(Quantity_Color)); }
- static void __testSize4() { Standard_STATIC_ASSERT (sizeof(float) * 4 == sizeof(Quantity_ColorRGBA)); }
+ static void myTestSize3() { Standard_STATIC_ASSERT (sizeof(float) * 3 == sizeof(Quantity_Color)); }
+ static void myTestSize4() { Standard_STATIC_ASSERT (sizeof(float) * 4 == sizeof(Quantity_ColorRGBA)); }
private:
|| aDepth >= ShortRealLast())
{
myImage->SetPixelColor (Standard_Integer(aColIter), Standard_Integer(aRowIter),
- NCollection_Vec4<float> (0.0f, 0.0f, 0.0f, 1.0f));
+ Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 1.0f));
continue;
}
aNormDepth = 1.0f - aNormDepth;
}
myImage->SetPixelColor (Standard_Integer(aColIter), Standard_Integer(aRowIter),
- NCollection_Vec4<float> (aNormDepth, aNormDepth, aNormDepth, 1.0f));
+ Quantity_ColorRGBA (aNormDepth, aNormDepth, aNormDepth, 1.0f));
}
}
}
if (thePicked < 1
|| thePicked > myMainSel->NbPicked())
{
- myImage->SetPixelColor (theCol, theRow, NCollection_Vec4<float> (0.0f, 0.0f, 0.0f, 1.0f));
+ myImage->SetPixelColor (theCol, theRow, Quantity_ColorRGBA (0.0f, 0.0f, 0.0f, 1.0f));
return;
}
const SelectMgr_SortCriterion& aSortCriterion = myMainSel->PickedData (thePicked);
const float aDepth = float(aSortCriterion.Depth);
- myImage->SetPixelColor (theCol, theRow, NCollection_Vec4<float> (aDepth, aDepth, aDepth, 1.0f));
+ myImage->SetPixelColor (theCol, theRow, Quantity_ColorRGBA (aDepth, aDepth, aDepth, 1.0f));
}
};
return 1;
}
- Quantity_Parameter anAlpha;
- Quantity_Color aColor = anImage.PixelColor (anX, anY, anAlpha);
+ Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY);
if (toShowName)
{
if (aBufferType == Graphic3d_BT_RGBA)
{
- theDI << Quantity_Color::StringName (aColor.Name()) << " " << anAlpha;
+ theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
}
else
{
- theDI << Quantity_Color::StringName (aColor.Name());
+ theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
}
}
else
{
if (toShowHls)
{
- theDI << aColor.Hue() << " " << aColor.Light() << " " << aColor.Saturation();
+ theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
}
else
{
- theDI << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue();
+ theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
}
break;
}
case Graphic3d_BT_RGBA:
{
- theDI << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << " " << anAlpha;
+ theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue() << " " << aColor.Alpha();
break;
}
case Graphic3d_BT_Depth:
{
- theDI << aColor.Red();
+ theDI << aColor.GetRGB().Red();
break;
}
}