Fuzzy Top Edge with GDIPlus Resize - c++

I'm using the following code to resize a bitmap using GDI+ in C. I'm getting gray values for the top edge even for images where that area should be white. The problem disappears when the interpolation is nearest neighbor. However, I tried bicubic interpolation with ImageMagick and it seems fine. Any limitations problems I should know of? Is my method of scaling wrong somehow? Thanks!
(inputs:
destSize : destination Gdiplus::Size
m_pBitmap : source bitmap)
Rect destRect(Point(0,0), destSize);
Bitmap *pBitmap24BPP = new Bitmap(destSize.Width, destSize.Height, PixelFormat24bppRGB);
pBitmap24BPP->SetResolution(m_pBitmap->GetHorizontalResolution(), m_pBitmap->GetVerticalResolution());
Graphics *pGraphics = Graphics::FromImage(pBitmap24BPP);
pGraphics->SetInterpolationMode(InterpolationModeHighQualityBilinear);
pGraphics->DrawImage(m_pBitmap, destRect, 0, 0, m_pBitmap->GetWidth(), m_pBitmap->GetHeight() , UnitPixel, NULL);
//cleanup

i've been seeing similar things. i've not had time to research it, but i have a feeling it is because the GDI+ image resizer is mistakenly using pixels values "off the top edge", which would be all zero - making it black.
Proper image resizing should recognize that you've reached the edge of the image, and handle it appropriately.

Related

Speeding up drawing bitmap magnification within second bitmap with blend

The following code stretches a bitmap, blends it with an existing background, maintains transparent area of primary graphic and then displays the blend within a window (imgScreen). This works fine when the level of stretch is not large or when it is actually shrinking the initial bitmap. However when stretching the graphic it is very slow.
I have limited experience with C++ and this kind of graphics so perhaps there is another more efficient way to do this. The primary bitmap to be sized is always square. Any ideas are much appreciated..!
I was going to try not displaying clipping area but from tests it seems the initial stretch is causing the slowdown... Also having trouble seeing how to calculate non clipped area... Drawing to controls seems a waste but seems only way to use built in functions like stretchdraw and the alpha draw option.
std::auto_ptr<Graphics::TBitmap> bmap(new Graphics::TBitmap);
std::auto_ptr<Graphics::TBitmap> bmap1(new Graphics::TBitmap);
int s = newsize;
TRect sR = Rect(X,Y,X+s,Y+s);
TRect tR = Rect(0,0,s,s);
bmap->SetSize(s,s);
bmap->Canvas->StretchDraw(Rect(0, 0, s, s), Form1->Image4->Picture-
>Bitmap); // scale
bmap1->SetSize(s,s);
bmap1->Canvas->CopyRect(tR, Form1->imgScreen->Canvas, sR); //background
bmap1->Canvas->Draw(0,0,bmap.get()); // combine
Form1->imgTemp->Picture->Assign(bmap1.get());
Form1->imgScreen->Canvas->Draw(X,Y, Form1->imgTemp->Picture->Bitmap,
alpha);
Displays correctly but as graphic gets larger draw rate slows down quickly...

Create mask to select the black area

I have a black area around my image and I want to create a mask using OpenCV C++ that selects just this black area so that I can paint it later. How can i do that without affecting the image itself?
I tried to convert the image to grayscale and then using threshold to convert it to binary, but it affects my image since the result contains black pixels from inside the image.
Another Question : if i want to crop the image instead of paint it, how can i do it??
Thanks in advance,
I would solve the problem like this:
Inverse-binarize the image with a threshold of 1 (i.e. all pixels with the value 0 are set to 1, all others to 0)
use cv::findContours to find white segments
remove segments that don't touch image borders
use cv::drawContours to draw the remaining segments to a mask.
There is probably a more efficient solution in terms of runtime efficiency, but you should be able to prototype my solution quite quickly.

How to thin an image borders with specific pixel size? OpenCV

I'm trying to thin an image by making the border pixels of size 16x24 becoming 0. I'm not trying to get the skeletal image, I'm just trying to reduce the size of the white area. Any methods that I could use? Enlighten me please.
This is the sample image that i'm trying to thin. It is made of 16x24 white blocks
EDIT
I tried to use this
cv::Mat img=cv::imread("image.bmp", CV_LOAD_IMAGE_GRAYSCALE);//image is in binary
cv::Mat mask = img > 0;
Mat kernel = Mat::ones( 16, 24, CV_8U );
erode(mask,mask,kernel);
But the result i got was this
which is not exactly what i wanted. I want to maintain the exact same shape with just 16x24 pixels of white shaved off from the border. Any idea what went wrong?
You want to Erode your image.
Another Description
Late answer, but you should erode your image using a kernel which is twice the size you want to get rid of plus one, like:
Mat kernel = Mat::ones( 24*2+1, 16*2+1, CV_8U );
Notice I changed the places of the height and width of the block, I only know opencv from Python, but I am pretty sure the order is the same as in Python.

SDL Transparent Overlay

I would like to create a fake "explosion" effect in SDL. For this, I would like the screen to go from what it is currently, and fade to white.
Originally, I thought about using SDL_FillRect like so (where explosionTick is the current alpha value):
SDL_FillRect(screen , NULL , SDL_MapRGBA(screen->format , 255, 255 , 255, explosionTick ));
But instead of a reverse fading rectangle, it shows up completely white with no alpha. The other method I tried involved using a fullscreen bitmap filled with a transparent white (with an alpha value of 1), and blit it once for each explosionTick like so:
for(int a=0; a<explosionTick; a++){
SDL_BlitSurface(boom, NULL, screen, NULL);
}
But, this ended up being to slow to run in real time.
Is there any easy way to achieve this effect without losing performance? Thank you for your time.
Well, you need blending and AFAIK the only way SDL does it is with SDL_Blitsurface. So you just need to optimize that blit. I suggest benchmarking those:
try to use SDL_SetAlpha to use per-surface alpha instead of per-pixel alpha. In theory, it's less work for SDL, so you may hope some speed gain. But I never compared it and had some problem with this in the past.
you don't really need a fullscreen bitmap, just repeat a thick row. It should be less memory intensive and maybe there is a cache gain. Also you can probably fake some smoothness by doing half the lines at each pass (less pixels to blit and should still look like a global screen effect).
for optimal performance, verify that your bitmap is at the display format. Check SDL_DisplayFormatAlpha or possibly SDL_DisplayFormat if you use per-surface alpha

transparent colour being shown some of the time

I am using a LPDIRECT3DTEXTURE9 to hold my image.
This is the function used to display my picture.
int drawcharacter(SPRITE& person, LPDIRECT3DTEXTURE9& image)
{
position.x = (float)person.x;
position.y = (float)person.y;
sprite_handler->Draw(
image,
&srcRect,
NULL,
&position,
D3DCOLOR_XRGB(255,255,255));
return 0;
}
According to the book I have the RGB colour shown as the last parameter will not be displayed on screen, this is how you create transparency.
This works for the most part but leaves a pink line around my image and the edge of the picture. After trial and error I have found that if I go back into photoshop I can eliminate the pink box by drawing over it with the pink colour. This can be see with the ships on the left.
I am starting to think that photoshop is blending the edges of the image so that background is not all the same shade of pink though I have no proof.
Can anyone help fix this by programming or is the error in the image?
If anyone is good at photoshop can they tell me how to fix the image, I use png mostly but am willing to change if necessary.
edit: texture creation code as requested
character_image = LoadTexture("character.bmp", D3DCOLOR_XRGB(255,0,255));
if (character_image == NULL)
return 0;
You are loading a BMP image, which does not support transparency natively - the last parameter D3DCOLOR_XRGB(255,0,255) is being used to add transparency to an image which doesn't have any. The problem is that the color must match exactly, if it is off even by only one it will not be converted to transparent and you will see the near-magenta showing through.
Save your images as 24-bit PNG with transparency, and if you load them correctly there will be no problems. Also don't add the magenta background before you save them.
As you already use PNG, you can just store the alpha value there directly from Photoshop. PNG supports transparency out of the box, and it can give better appearance than what you get with transparent colour.
It's described in http://www.toymaker.info/Games/html/textures.html (for example).
Photoshop is anti-aliasing the edge of the image. If it determines that 30% of a pixel is inside the image and 70% is outside, it sets the alpha value for that pixel to 70%. This gives a much smoother result than using a pixel-based transparency mask. You seem to be throwing these alpha values away, is that right? The pink presumably comes from the way that Photoshop displays partially transparent pixels.