OpenCV zooming in on Mat image without the window border changing c++ - c++

I have a window Mat gestures containing an image, I want to zoom in every pixel in the window but keep the border the same size. I have tried resize() but it's resizing the border as well.
For better explanation, I don't want the border that is in the green box to be resized as well as the whole border, but I need the image inside the border to be resized. How can I achieve this?

Set a ROI of the image excluding the border. If you already know the thickness, simply assign a new img from it. Then you can resize and draw cv::rectangle with the thickness of original image.
Following code snippet may not compile since I don't see a reproducible code.
cv::Mat img = cv::imread(...);
const int thick = 3;
const cv::Rect roi(thick, thick, img.width()-2*thick, img.height()-2*thick);
cv::Mat img_roi = img(roi);
cv::resize(...); // resize img_roi
cv::rectangle(...); // draw new border on img_roi, you need to pass a cv::Scalar value from img.at(0, 0) for the color of it.
However, I'm expecting a better idea from someone else.

The basic idea is deciding the scale changed every time on mouse wheel. After you get the current scale (v.s. origin image), you then can get the position and length of rectangle on scaled image.
In my github,checking OnMouseWheel () and RefreshSrcView () in Fastest_Image_Pattern_Matching/ELCVMatchTool/ELCVMatchToolDlg.cpp may give what you want.
Besides, if you only want to use opencv window without MFC framework or other frameworks, check this (pure OpenCV version)
Effect:
Part of the code:
BOOL CELCVMatchToolDlg::OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)
{
POINT pointCursor;
GetCursorPos (&pointCursor);
ScreenToClient (&pointCursor);
// TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
if (zDelta > 0)
{
if (m_iScaleTimes == MAX_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes++;
}
if (zDelta < 0)
{
if (m_iScaleTimes == MIN_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes--;
}
CRect rect;
//GetWindowRect (rect);
GetDlgItem (IDC_STATIC_SRC_VIEW)->GetWindowRect (rect);//重要
if (m_iScaleTimes == 0)
g_dCompensationX = g_dCompensationY = 0;
int iMouseOffsetX = pt.x - (rect.left + 1);
int iMouseOffsetY = pt.y - (rect.top + 1);
double dPixelX = (m_hScrollBar.GetScrollPos () + iMouseOffsetX + g_dCompensationX) / m_dNewScale;
double dPixelY = (m_vScrollBar.GetScrollPos () + iMouseOffsetY + g_dCompensationY) / m_dNewScale;
m_dNewScale = m_dSrcScale * pow (SCALE_RATIO, m_iScaleTimes);
if (m_iScaleTimes != 0)
{
int iWidth = m_matSrc.cols;
int iHeight = m_matSrc.rows;
m_hScrollBar.SetScrollRange (0, int (m_dNewScale * iWidth - m_dSrcScale * iWidth) - 1 + BAR_SIZE);
m_vScrollBar.SetScrollRange (0, int (m_dNewScale * iHeight - m_dSrcScale * iHeight) - 1 + BAR_SIZE);
int iBarPosX = int (dPixelX * m_dNewScale - iMouseOffsetX + 0.5);
m_hScrollBar.SetScrollPos (iBarPosX);
m_hScrollBar.ShowWindow (SW_SHOW);
g_dCompensationX = -iBarPosX + (dPixelX * m_dNewScale - iMouseOffsetX);
int iBarPosY = int (dPixelY * m_dNewScale - iMouseOffsetY + 0.5);
m_vScrollBar.SetScrollPos (iBarPosY);
m_vScrollBar.ShowWindow (SW_SHOW);
g_dCompensationY = -iBarPosY + (dPixelY * m_dNewScale - iMouseOffsetY);
//滑塊大小
SCROLLINFO infoH;
infoH.cbSize = sizeof (SCROLLINFO);
infoH.fMask = SIF_PAGE;
infoH.nPage = BAR_SIZE;
m_hScrollBar.SetScrollInfo (&infoH);
SCROLLINFO infoV;
infoV.cbSize = sizeof (SCROLLINFO);
infoV.fMask = SIF_PAGE;
infoV.nPage = BAR_SIZE;
m_vScrollBar.SetScrollInfo (&infoV);
//滑塊大小
}
else
{
m_hScrollBar.SetScrollPos (0);
m_hScrollBar.ShowWindow (SW_HIDE);
m_vScrollBar.SetScrollPos (0);
m_vScrollBar.ShowWindow (SW_HIDE);
}
RefreshSrcView ();
return CDialogEx::OnMouseWheel (nFlags, zDelta, pt);
}

Related

Calculate text size

Note: This question How to put text into a bounding box in OpenCV? is in some ways similar to this one but it is not the same question. The OP of the questions tried to spread a text to the whole size of his image & the code in the answer that gots the mark is just resizing the text using a mask.
I'm using openCV combined with C++ to do some image detection & manipulation.
So I want to align a text with a unknown length at a specific origin. The font-scale should be calculated because I'd like to specify a width factor for the maximum Text-width like you can see in the image below:
This is the code I got so far:
int fontFace = cv::FONT_HERSHEY_DUPLEX,
fontScale = myTextString.size() / 10;
cv::Size textSize = getTextSize(image, fontFace, fontScale, 0, 0);
putText(image, myTextString, cv::Point( (origin.x + textSize.width)/2, (origin.y + textSize.height)/2 ), fontFace, fontScale, Scalar(255, 0, 0));
Something like this should do it. You can change how the margins are calculated to change the horizontal/vertical alignment of the font.
If the height doesn't matter, you can just leave target.height a large number.
void drawtorect(cv::Mat & mat, cv::Rect target, int face, int thickness, cv::Scalar color, const std::string & str)
{
cv::Size rect = cv::getTextSize(str, face, 1.0, thickness, 0);
double scalex = (double)target.width / (double)rect.width;
double scaley = (double)target.height / (double)rect.height;
double scale = std::min(scalex, scaley);
int marginx = scale == scalex ? 0 : (int)((double)target.width * (scalex - scale) / scalex * 0.5);
int marginy = scale == scaley ? 0 : (int)((double)target.height * (scaley - scale) / scaley * 0.5);
cv::putText(mat, str, cv::Point(target.x + marginx, target.y + target.height - marginy), face, scale, color, thickness, 8, false);
}
* edit *
// Sample code
int L = 80; // width and height per square
int M = 60;
cv::Mat m( 5*M, 7*L,CV_8UC3,cv::Scalar(0,0,0) );
// create checkerboard
for ( int y=0,ymax=m.rows-M;y<=ymax; y+=M)
{
int c = (y/M)%2 == 0 ? 0 : 1;
for ( int x=0,xmax=m.cols-L;x<=xmax;x+=L)
{
if ( (c++)%2!=0 )
continue; // skip odd squares
// convenient way to do this
m( cv::Rect(x,y,L,M) ).setTo( cv::Scalar(64,64,64) );
}
}
// fill checkerboard ROIs by some text
int64 id=1;
for ( int y=0,ymax=m.rows-M;y<=ymax; y+=M)
{
for ( int x=0,xmax=m.cols-L;x<=xmax;x+=L)
{
std::stringstream ss;
ss<<(id<<=1); // some increasing text input
drawtorect( m, cv::Rect(x,y,L,M), cv::FONT_HERSHEY_PLAIN,1,cv::Scalar(255,255,255),ss.str() );
}
}

Qt Window incorrect size until user event

I'm creating a screen where users can add certain tiles to use in an editor, but when adding a tile the window does not correctly resize to fit the content. Except that when I drag the window or resize it even just a little then it snaps to the correct size immediately.
And when just dragging the window it snaps to the correct size.
I tried using resize(sizeHint()); which gave me an incorrect size and the following error, but the snapping to correct size still happens when resizing/dragging.
QWindowsWindow::setGeometry: Unable to set geometry 299x329+991+536 on QWidgetWindow/'TileSetterWindow'. Resulting geometry: 299x399+991+536 (frame: 8, 31, 8, 8, custom margin: 0, 0, 0, 0, minimum size: 259x329, maximum size: 16777215x16777215).
I also tried using updateGeometry() and update(), but it didn't seem to do much if anything.
When setting the window to fixedSize it will immediately resize, but then the user cannot resize the window anymore. What am I doing wrong here and where do I start to solve it?
Edit
Minimal verifiable example and the .ui file.
selected_layout is of type Flowlayout
The flowlayout_placeholder_1 is only there because I can't place a flowlayout directly into the designer.
Edit2
Here is a minimal Visual Studio example. I use Visual Studio for Qt development. I tried creating a project in Qt Creator, but I didn't get that to work.
Edit3
Added a little video (80 KB).
Edit4
Here is the updated Visual Studio example. It has the new changes proposed by jpo38. It fixes the issue of the bad resizing. Though now trying to downsize the windows causes issues. They don't correctly fill up vertical space anymore if you try to reduce the horizontal space even though there is room for more rows.
Great MCVE, exactly what's needed to easily investigate the issue.
Looks like this FlowLayout class was not designed to have it's minimum size change on user action. Layout gets updated 'by chance' by QWidget kernel when the window is moved.
I could make it work smartly by modifying FlowLayout::minimumSize() behaviour, here are the changes I did:
Added QSize minSize; attribute to FlowLayout class
Modifed FlowLayout::minimumSize() to simply return this attribute
Added a third parameter QSize* pMinSize to doLayout function. This will be used to update this minSize attribute
Modified doLayout to save computed size to pMinSize parameter if specified
Had FlowLayout::setGeometry pass minSize attribute to doLayout and invalidate the layout if min size changed
The layout then behaves as expected.
int FlowLayout::heightForWidth(int width) const {
const int height = doLayout(QRect(0, 0, width, 0), true,NULL); // jpo38: set added parameter to NULL here
return height;
}
void FlowLayout::setGeometry(const QRect &rect) {
QLayout::setGeometry(rect);
// jpo38: update minSize from here, force layout to consider it if it changed
QSize oldSize = minSize;
doLayout(rect, false,&minSize);
if ( oldSize != minSize )
{
// force layout to consider new minimum size!
invalidate();
}
}
QSize FlowLayout::minimumSize() const {
// jpo38: Simply return computed min size
return minSize;
}
int FlowLayout::doLayout(const QRect &rect, bool testOnly,QSize* pMinSize) const {
int left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
int x = effectiveRect.x();
int y = effectiveRect.y();
int lineHeight = 0;
// jpo38: store max X
int maxX = 0;
for (auto&& item : itemList) {
QWidget *wid = item->widget();
int spaceX = horizontalSpacing();
if (spaceX == -1)
spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
int spaceY = verticalSpacing();
if (spaceY == -1)
spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
int nextX = x + item->sizeHint().width() + spaceX;
if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
x = effectiveRect.x();
y = y + lineHeight + spaceY;
nextX = x + item->sizeHint().width() + spaceX;
lineHeight = 0;
}
if (!testOnly)
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
// jpo38: update max X based on current position
maxX = qMax( maxX, x + item->sizeHint().width() - rect.x() + left );
x = nextX;
lineHeight = qMax(lineHeight, item->sizeHint().height());
}
// jpo38: save height/width as max height/xidth in pMinSize is specified
int height = y + lineHeight - rect.y() + bottom;
if ( pMinSize )
{
pMinSize->setHeight( height );
pMinSize->setWidth( maxX );
}
return height;
}
I was having the same exact issue (albeit on PySide2 rather than C++).
#jpo38's answer above did not work directly, but it un-stuck me by giving me a new approach.
What worked was storing the last geometry, and using that geometry's width to calculate the minimum height.
Here is an untested C++ implementation based on the code in jpo38's answer (I don't code much in C++ so apologies in advance if some syntax is wrong):
int FlowLayout::heightForWidth(int width) const {
const int height = doLayout(QRect(0, 0, width, 0), true);
return height;
}
void FlowLayout::setGeometry(const QRect &rect) {
QLayout::setGeometry(rect);
// e-l: update lastSize from here
lastSize = rect.size();
doLayout(rect, false);
}
QSize FlowLayout::minimumSize() const {
// e-l: Call heightForWidth from here, my doLayout is doing things a bit differently with regards to margins, so might have to add or not add the margins here to the height
QSize size;
for (const QLayoutItem *item : qAsConst(itemList))
size = size.expandedTo(item->minimumSize());
const QMargins margins = contentsMargins();
size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom());
size.setHeight(heightForWidth(qMax(lastSize.width(), size.width())));
return size;
}
int FlowLayout::doLayout(const QRect &rect, bool testOnly) const {
int left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
int x = effectiveRect.x();
int y = effectiveRect.y();
int lineHeight = 0;
for (auto&& item : itemList) {
QWidget *wid = item->widget();
int spaceX = horizontalSpacing();
if (spaceX == -1)
spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
int spaceY = verticalSpacing();
if (spaceY == -1)
spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
int nextX = x + item->sizeHint().width() + spaceX;
if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
x = effectiveRect.x();
y = y + lineHeight + spaceY;
nextX = x + item->sizeHint().width() + spaceX;
lineHeight = 0;
}
if (!testOnly)
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
x = nextX;
lineHeight = qMax(lineHeight, item->sizeHint().height());
}
int height = y + lineHeight - rect.y() + bottom;
return height;
}

Shrinking images using recursion incorrect positioning

I am writing code that takes an image and creates subimages within the original image. I am doing this recursively with a rectangle class that keeps track of starting and stopping positions of the subimage. After the 3rd recursive call is where i run into trouble. The new subimages are being placed in the incorrect spots. They should be shrinking as they approach the top right corner of the image. I have run through the debugger and watched the start and stop positions change with each call and they reflect movement toward the top right corner. The only place I think the error could be is where I create a new rectangle called rRight to be put into the recursive call.
int main()
{
CImage original("test256.gif");
Rectangle rPrev(0, 0, original.getRows(), original.getCols());
Rectangle r(0, 0, (original.getRows() / 2), (original.getCols() / 2));
CImage final = fractal(original, r, rPrev);
final.output("output.gif");
system("PAUSE");
return 0;
}
CImage fractal(CImage &origin, Rectangle &r, Rectangle &rPrev)
{
if (r.getX2() - r.getX1() > 0 && r.getY2() - r.getY1() > 0)
{
drawTopLeft(origin, r, rPrev);
Rectangle rRight(0, r.getY2(), (r.getX2() / 2), (r.getY2() + ((r.getY2() - r.getY1()) / 2)));
fractal(origin, rRight, r);
}
return origin;
}
void drawTopLeft(CImage &origin, Rectangle &r, Rectangle &rPrev)
{
for (int row = rPrev.getX1(); row < rPrev.getX2(); row += 2)
{
for (int col = rPrev.getY1(); col < rPrev.getY2(); col += 2)
{
pixel p1 = origin.getPixel(row, col);
pixel p2 = origin.getPixel(row + 1, col);
pixel p3 = origin.getPixel(row, col + 1);
pixel p4 = origin.getPixel(row + 1, col + 1);
int avgRed = (p1.red + p2.red + p3.red + p4.red) / 4;
int avgGreen = (p1.green + p2.green + p3.green + p4.green) / 4;
int avgBlue = (p1.blue + p2.blue + p3.blue + p4.blue) / 4;
origin.setPixel((row / 2) + r.getX1(), (col / 2) + r.getY1(), avgRed, avgGreen, avgBlue);
}
}
}

SDL - drawing 'negative' circles (Fog of War)

I have this 800x600square I want to draw to the screen. I want to 'cut' circles in it (where alpha would be 0). Basically I'm drawing this whole rectangle over a map so in these 'circles' I drew, you can see the map, otherwise you see the grey square
So, I assume you're trying to add fog of war to one of you game?
I had a small demo I made for a local University a few weeks ago to show A* pathfinding, so I thought I could add fog of war to it for you. Here's the results:
Initial map
First, you start with a complete map, totally visible
Fog
Then, I added a surface to cover the entire screen (take note that my map is smaller than the screen, so for this case I just added fog of war on the screen, but if you have scrolling, make sure it covers each map pixel 1:1)
mFogOfWar = SDL_CreateRGBSurface(SDL_HWSURFACE, in_Width, in_Height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
SDL_Rect screenRect = {0, 0, in_Width, in_Height};
SDL_FillRect(mFogOfWar, &screenRect, 0xFF202020);
Then, you need to draw it... I added this call after drawing the game objects and before drawing the UI
DrawSurface(mFogOfWar, 0, 0);
Where
void RenderingManager::DrawSurface(SDL_Surface* in_Surface, int in_X, int in_Y)
{
SDL_Rect Dest = { in_X, in_Y, 0, 0 };
SDL_BlitSurface(in_Surface, NULL, mScreen, &Dest);
}
Which should give you the following result:
"Punch Surface"
I then created a 32 bits .png that looks like this (checkerboard shows alpha)
When rendering my main character, I added this call:
gRenderingManager.RemoveFogOfWar(int(mX) + SPRITE_X_OFFSET, int(mY) + SPRITE_Y_OFFSET);
The offset is only there to center the punch with the sprite, basically, what I'm passing to RemoveFogOfWar is the center of my sprite.
Remove Fog Of War
Now the meat of the fog of war. I did two versions, one where Fog of War is removed permanently and one where the fog of war is reset. My fog of war reset relies on my punch surface to have a contour where the alpha is reset to 0 and the fact that my character moves of less pixels than the contour contains per frame, otherwise I would keep the Rect where my punch was applied and I would refill it before drawing again the new punch.
Since I couldn't find a "multiply" blend with SDL, I decided to write a simple function that iterates on the punch surface and updates the alpha on the fog of war surface. The most important part is to make sure you stay within the bounds of your surfaces, so it takes up most of the code... there might be some crop functions but I didn't bother checking:
void RenderingManager::RemoveFogOfWar(int in_X, int in_Y)
{
const int halfWidth = mFogOfWarPunch->w / 2;
const int halfHeight = mFogOfWarPunch->h / 2;
SDL_Rect sourceRect = { 0, 0, mFogOfWarPunch->w, mFogOfWarPunch->h };
SDL_Rect destRect = { in_X - halfWidth, in_Y - halfHeight, mFogOfWarPunch->w, mFogOfWarPunch->h };
// Make sure our rects stays within bounds
if(destRect.x < 0)
{
sourceRect.x -= destRect.x; // remove the pixels outside of the surface
sourceRect.w -= sourceRect.x; // shrink to the surface, not to offset fog
destRect.x = 0;
destRect.w -= sourceRect.x; // shrink the width to stay within bounds
}
if(destRect.y < 0)
{
sourceRect.y -= destRect.y; // remove the pixels outside
sourceRect.h -= sourceRect.y; // shrink to the surface, not to offset fog
destRect.y = 0;
destRect.h -= sourceRect.y; // shrink the height to stay within bounds
}
int xDistanceFromEdge = (destRect.x + destRect.w) - mFogOfWar->w;
if(xDistanceFromEdge > 0) // we're busting
{
sourceRect.w -= xDistanceFromEdge;
destRect.w -= xDistanceFromEdge;
}
int yDistanceFromEdge = (destRect.y + destRect.h) - mFogOfWar->h;
if(yDistanceFromEdge > 0) // we're busting
{
sourceRect.h -= yDistanceFromEdge;
destRect.h -= yDistanceFromEdge;
}
SDL_LockSurface(mFogOfWar);
Uint32* destPixels = (Uint32*)mFogOfWar->pixels;
Uint32* srcPixels = (Uint32*)mFogOfWarPunch->pixels;
static bool keepFogRemoved = false;
for(int x = 0; x < destRect.w; ++x)
{
for(int y = 0; y < destRect.h; ++y)
{
Uint32* destPixel = destPixels + (y + destRect.y) * mFogOfWar->w + destRect.x + x;
Uint32* srcPixel = srcPixels + (y + sourceRect.y) * mFogOfWarPunch->w + sourceRect.x + x;
unsigned char* destAlpha = (unsigned char*)destPixel + 3; // fetch alpha channel
unsigned char* srcAlpha = (unsigned char*)srcPixel + 3; // fetch alpha channel
if(keepFogRemoved == true && *srcAlpha > 0)
{
continue; // skip this pixel
}
*destAlpha = *srcAlpha;
}
}
SDL_UnlockSurface(mFogOfWar);
}
Which then gave me this with keepFogRemoved = false even after the character had moved around
And this with keepFogRemoved = true
Validation
The important part is really to make sure you don't write outside of your pixel buffer, so watch out with negative offsets or offsets that would bring you out of the width or height. To validate my code, I added a simple call to RemoveFogOfWar when the mouse is clicked and tried corners and edges to make sure I didn't have a "off by one" problem
case SDL_MOUSEBUTTONDOWN:
{
if(Event.button.button == SDL_BUTTON_LEFT)
{
gRenderingManager.RemoveFogOfWar(Event.button.x, Event.button.y);
}
break;
}
Notes
Obviously, you don't need a 32 bits texture for the "punch", but it was the clearest way I could think of to show you how to do it. It could be done using as little as 1 bit per pixel (on / off). You can also add some gradient, and change the
if(keepFogRemoved == true && *srcAlpha > 0)
{
continue; // skip this pixel
}
To something like
if(*srcAlpha > *destAlpha)
{
continue;
}
To keep a smooth blend like this:
3 State Fog of War
I thought I should add this... I added a way to create a 3 state fog of war: visible, seen and fogged.
To do this, I simply keep the SDL_Rect of where I last "punched" the fog of war, and if the alpha is lower than a certain value, I clamp it at that value.
So, by simply adding
for(int x = 0; x < mLastFogOfWarPunchPosition.w; ++x)
{
for(int y = 0; y < mLastFogOfWarPunchPosition.h; ++y)
{
Uint32* destPixel = destPixels + (y + mLastFogOfWarPunchPosition.y) * mFogOfWar->w + mLastFogOfWarPunchPosition.x + x;
unsigned char* destAlpha = (unsigned char*)destPixel + 3;
if(*destAlpha < 0x60)
{
*destAlpha = 0x60;
}
}
}
mLastFogOfWarPunchPosition = destRect;
right before the loop where the fog of war is "punched", I get a fog of war similar to what you could have in games like StarCraft:
Now, since the "seen" fog of war is semi transparent, you will need to tweak your rendering method to properly clip "enemies" that would be in the fog, so you don't see them but you still see the terrain.
Hope this helps!

How to change image's alpha value without completely reloading every pixel each frame/ OPTIMIZATION

so I'm trying to bring an image to visibility in sfml 1.6 by changing it's alpha value every frame. unfortunately there isn't an overall alpha value for the image, so i have to go through each pixel, one by one and change it's alpha value.
This is extremely slow however, so I wondering how I could possibly optimize my simple code, or if there was another sfml specific way to handle this.
anyway here's the code:
Each new frame I Recolor a sprite with a added alpha value of 1.7.
// #Return Ptr: a pointer to the stack allocated image so the
// user can deallocate it later
sf::Image* RecolorSprite(sf::Sprite& sprite, sf::Color filter, bool subtract){
// the image has to survive so it's put ont he stack
sf::Image* image = new sf::Image;
*image = *sprite.GetImage();
RecolorImage(*image, filter, subtract);
sprite.SetImage(*image);
return image;
}
void RecolorImage(sf::Image& image, sf::Color filter, bool subtract){
for( int x= 0; x< image.GetWidth(); x++){
for(int y= 0; y< image.GetHeight(); y++){
if(subtract){
sf::Color pixel = image.GetPixel(x, y);
SubtractColor(pixel, filter);
image.SetPixel(x, y, pixel);
}
else
image.SetPixel(x, y, image.GetPixel(x, y) + filter);
}
}
}
// int used to stop illegal operations on unsigned chars
void SubtractColor(sf::Color& col1, sf::Color& col2){
int diff = ((int)col1.r) - ((int)col2.r);
if(diff >= 0)
col1.r -= col2.r;
else
col1.r = 0;
diff = ((int)col1.g) - ((int)col2.g);
if(diff >= 0)
col1.g -= col2.g;
else
col1.g = 0;
diff = ((int)col1.b) - ((int)col2.b);
if(diff >= 0)
col1.b -= col2.b;
else
col1.b = 0;
diff = ((int)col1.a) - ((int)col2.a);
if(diff >= 0)
col1.a -= col2.a;
else
col1.a = 0;
}
Unless I'm misunderstanding your question, you should be able to use sf::Drawable::SetColor for this, giving white as the argument but with a differing alpha value. For instance, to set sprite's alpha to 50%, you could do the following:
sprite.SetColor(sf::Color(255, 255, 255, 128));