Various thresholds - image

I am trying to track multiple objects with different color at the same time via a single web cam. Now I can do that for single color with single threshold:
IplImage* GetThresholdedImage(IplImage* imgHSV)
{
IplImage* imgThresh=cvCreateImage(cvGetSize(imgHSV),IPL_DEPTH_8U, 1);
cvInRangeS(imgHSV, cvScalar(170,160,60), cvScalar(180,2556,256), imgThresh);
return imgThresh;
}
I'm looking for some hints to do various threshold. Also if its possible, how many windows does it require? Do i need to assign different windows for different colors?

The easiest way to do this is create a thresholded image for each color you wish to track. Instead of hard-coding your threshold ranges, you could modify your function to take them as parameters. This lets you re-use the function for different objects.
The modified function might look like this:
IplImage* GetThresholdedImage(IplImage* imgHSV, CvScalar lower, CvScalar upper)
{
IplImage* imgThresh=cvCreateImage(cvGetSize(imgHSV),IPL_DEPTH_8U, 1);
cvInRangeS(imgHSV, lower, upper, imgThresh);
return imgThresh;
}
And then call it using different thresholds for different objects:
IplImage* hsv; /* Already initialized*/
/* Set thresholds for blue and green objects as an example. */
/*Obviously, set these to be whatever is necessary. */
CvScalar blue_lower = cvScalar(110,60,10);
CvScalar blue_upper = cvScalar(120,256,256);
CvScalar green_lower = cvScalar(40,60,10);
CvScalar green_upper = cvScalar(71,256,256);
/* Get the images thresholded for blue and green. */
IplImage* blue_mask = GetThresholdedImage(hsv, blue_lower, blue_upper);
IplImage* green_mask = GetThresholdedImage(hsv, green_lower, green_upper);

Related

How can I get rid of artifacts in ImageSource created with SkiaSharp

I created an app in which I want to display text on top of google maps. I chose to use custom markers, but they can only be images, so I decided to create an image from my text utilizing SkiaSharp.
private static ImageSource CreateImageSource(string text)
{
int numberSize = 20;
int margin = 5;
SKBitmap bitmap = new SKBitmap(30, numberSize + margin * 2, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
SKCanvas canvas = new SKCanvas(bitmap);
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.StrokeAndFill,
TextSize = numberSize,
Color = SKColors.Red,
StrokeWidth = 1,
};
canvas.DrawText(text.ToString(), 0, numberSize, paint);
SKImage skImage = SKImage.FromBitmap(bitmap);
SKData data = skImage.Encode(SKEncodedImageFormat.Png, 100);
return ImageSource.FromStream(data.AsStream);
}
The images I create however have ugly artifacts on the top of the resulting image and my feeling is that they get worse if I create multiple images.
I built an example app, that shows the artifacts and the code I used to draw the text. It can be found here:
https://github.com/hot33331/SkiaSharpExample
How can I get rid of those artifacts. Am I using skia wrong?
I got the following answer from Matthew Leibowitz on the SkiaSharp GitHub:
The chances are you are not clearing the canvas/bitmap first.
You can either do bitmap.Erase(SKColors.Transparent) or canvas.Clear(SKColors.Transparent) (you can use any color).
The reason for this is performance. When creating a new bitmap, the computer has no way of knowing what background color you want. So, if it was to go transparent and you wanted white, then there would be two draw operations to clear the pixels (and this may be very expensive for large images).
During the allocation of the bitmap, the memory is provided, but the actual data is untouched. If there was anything there previously (which there will be), this data appears as colored pixels.
When I've seen that before, it's been because the memory passed to SkiaSharp was not zeroed. As an optimization, though, Skia assumes that the memory block passed to it is pre zeroed. Resultingly, if your first operation is a clear, it will ignore that operation, because it thinks that the state is already clean. To resolve this issue, you can manually zero the memory passed to SkiaSharp.
public static SKSurface CreateSurface(int width, int height)
{
// create a block of unmanaged native memory for use as the Skia bitmap buffer.
// unfortunately, this may not be zeroed in some circumstances.
IntPtr buff = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(width * height * 4);
byte[] empty = new byte[width * height * 4];
// copy in zeroed memory.
// maybe there's a more sanctioned way to do this.
System.Runtime.InteropServices.Marshal.Copy(empty, 0, buff, width * height * 4);
// create the actual SkiaSharp surface.
var colorSpace = CGColorSpace.CreateDeviceRGB();
var bContext = new CGBitmapContext(buff, width, height, 8, width * 4, colorSpace, (CGImageAlphaInfo)bitmapInfo);
var surface = SKSurface.Create(width, height, SKColorType.Rgba8888, SKAlphaType.Premul, bitmap.Data, width * 4);
return surface;
}
Edit: btw, I assume this is a bug in SkiaSharp. The samples/apis that create the buffer for you should probably be zeroing it out. Depending on the platform it can be hard to repro as the memory alloc behaves differently. More or less likely to provide you untouched memory.

Visual C++: Good way to draw and animated fill path to screen?

I want to use Visual C++ to animate fill paths to screen. I have done it with C# before, but now switch to C++ for better perfomance and want do more complex works in the future.
Here is the concept in C#:
In a Canvas I have a number of Path. These paths are closed geometries combine of LineTo and QuadraticBezierTo functions.
Firstly, I fill Silver color for all path.
Then for each path, I fill Green color from one end to other end (up/down/left/right direction) (imagine a progress bar increase its value from min to max). I do it by set the Fill brush of the path to a LinearGradientBrush with two color Green and Silver with same offset, then increase the offset from 0 to 1 by Timer.
When a path is fully green, continue with next path.
When all path is fill with Green, come back first step.
I want to do same thing in Visual C++. I need to know an effective way to:
Create and store paths in a collection to reuse. Because the path is quite lot of point, recreate them repeatly take lots of CPU usage.
Draw all paths to a window.
Do animation fill like step 2, 3, 4 in above concept.
So, what I need is:
A suitable way to create and store closed paths. Note: paths are combine of points connect by functions same with C# LineTo and QuadraticBezierTo function.
Draw and animated fill the paths to screen.
Can you please suggest one way to do above step? (outline what I have to read, then I can study about it myself). I know basic of Visual C++, Win32 GUI and a little about draw context (HDC) and GDI, but only start to learn Graphic/Drawing.
Sorry about my English! If anythings I explain dont clear, please let me know.
how many is quite lot of point ? what is the target framerate? for low enough counts you can use GDI for this otherwise you need HW acceleration like OpenGL,DirectX.
I assume 2D so You need:
store your path as list of segments
for example like this:
struct path_segment
{
int p0[2],p1[2],p2[2]; // points
int type; // line/bezier
float length; // length in pixels or whatever
};
const int MAX=1024; // max number of segments
path_segment path[MAX]; // list of segments can use any template like List<path_segment> path; instead
int paths=0; // actual number of segments;
float length=0.0; // while path length in pixels or whatever
write functions to load and render path[]
The render is just for visual check if you load is OK ... for now atlest
rewrite the render so
it take float t=<0,1> as input parameter which will render path below t with one color and the rest with other. something like this:
int i;
float l=0.0,q,l0=t*length; // separation length;
for (i=0;i<paths;i++)
{
q=l+path[i].length;
if (q>=l0)
{
// split/render path[i] to < 0,l-l0> with color1
// split/render path[i] to <l-l0,q-l0> with color2
// if you need split parameter in <0,1> then =(l-l0)/path[i].length;
i++; break;
}
else
{
//render path[i] with color1
}
l=q;
}
for (;i<paths;i++)
{
//render path[i] with color2
}
use backbuffer for speedup
so render whole path with color1 to some bitmap. On each animation step just render the newly added color1 stuff. And on each redraw just copy the bitmap to screen instead of rendering the same geometry over and over. Of coarse if you have zoom/pan/resize capabilities you need to redraw the bitmap fully on each of those changes ...

How to create an imagelist from a PNG?

I've seen here that you can create an image list with transparency. It works... sort of.
I used this to create an image list for a list control. The results were a little disappointing:
The one on the left is how it should look. The one on the right is how the list control is displaying it. It looks like it just tried to use the alpha as a mask and any blended area is attempted to be approximated by dithering. Is there a way of getting this better so that I get an actual alpha blended image?
Here is the source if that makes any difference:
class CDlg : public CDialog
{
DECLARE_DYNCREATE(CDlg)
public:
CDlg(CWnd* pParent = NULL); // standard constructor
virtual ~CDlg();
// Dialog Data
enum { IDD = IDD_BS_PRINT };
CGdiPlusBitmapResource m_pBitmap;
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
public:
CListCtrl m_printOptions;
};
BOOL CDlg::OnInitDialog()
{
__super::OnInitDialog();
m_pBitmap.Load(IDB_RIBBON_HOMELARGE, _T("PNG"), AfxGetResourceHandle());
HBITMAP hBitmap;
m_pBitmap.m_pBitmap->GetHBITMAP(RGB(0, 0, 0), &hBitmap);
CImageList *pList = new CImageList;
CBitmap bm;
bm.Attach(hBitmap);
pList->Create(32, 32, ILC_COLOR32, 0, 4);
pList->Add(&bm, RGB(255, 0, 255));
m_printOptions.SetImageList(pList, LVSIL_NORMAL);
//...
return TRUE;
}
IMPLEMENT_DYNCREATE(CDlg, CDialog)
CBSPrintDlg::CBSPrintDlg(CWnd* pParent /*=NULL*/)
: CBCGPDialog(CBSPrintDlg::IDD, pParent)
{
}
CBSPrintDlg::~CBSPrintDlg()
{
}
void CBSPrintDlg::DoDataExchange(CDataExchange* pDX)
{
CBCGPDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PRINT_OPTIONS, m_printOptions);
}
For source of CGdiPlusBitmapResource implementation look here.
The original image with transparency is this:
#Barmak tried with a different image and it looks fine. I think that is because the transparency is near the edge and not located within the image. See here:
Edit ----------
First parameter in Gdiplus::GetHBITMAP should be the background color. Using RGB(0, 0, 0) as background color causes the semi-transparent pixels to match with black.
Using Gdiplus::Color(255,255,255,255) (white) it will improve the appearance (because ListView background is also white). But it's better to change the background to Gdiplus::Color(0,255,255,255) (transparent) to match any background.
{
CGdiPlusBitmapResource gdibmp;
if (gdibmp.Load(IDB_RIBBON_HOMELARGE, _T("PNG"), AfxGetResourceHandle()))
{
HBITMAP hBitmap;
gdibmp.m_pBitmap->GetHBITMAP(Gdiplus::Color::Transparent, &hBitmap);
ImageList_AddMasked(*pList, hBitmap, 0);
}
}
This assume images are all 32x32 pixels. If images are different sizes, they have to be resized before being added to image list.
{
CGdiPlusBitmapResource gdibmp;
if (gdibmp.Load(id, _T("PNG"), AfxGetResourceHandle()))
{
//resize image to 32x32 pixels
Gdiplus::Bitmap newBmp(32, 32, PixelFormat32bppPARGB);
double oldh = (double)gdibmp.m_pBitmap->GetHeight();
double oldw = (double)gdibmp.m_pBitmap->GetWidth();
double neww = 32;
double newh = 32;
double ratio = oldw / oldh;
if (oldw > oldh)
newh = neww / ratio;
else
neww = newh * ratio;
Gdiplus::Graphics graphics(&newBmp);
graphics.SetInterpolationMode(Gdiplus::InterpolationMode::InterpolationModeHighQualityBicubic);
graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
graphics.DrawImage(gdibmp.m_pBitmap, 0, 0, (int)neww, (int)newh);
//add `newBmp` to image list
HBITMAP hBitmap;
newBmp.GetHBITMAP(Gdiplus::Color::Transparent, &hBitmap);
ImageList_AddMasked(m_ImageList, hBitmap, 0);
}
}
Using GdiPlus::GetHICON to get the icon handle... With CGdiPlusBitmapResource class, it should be possible to use the following:
HICON hicon;
m_pBitmap.Load(IDB_RIBBON_HOMELARGE, _T("PNG"), AfxGetResourceHandle());
m_pBitmap.m_pBitmap->GetHICON(&hicon);
pList->Add(hicon);
or using GetHBITMAP
Also make sure Visual Styles is enabled for improved appearance of ListView icons.
Test image with transparent background:
The PNG image contains pixels that are partially transparent (alpha < 255). That's a pretty common accident with a program like Photoshop, the most likely cause is overlaying the spyglass image on top of the document image and not merging the layers correctly.
As given, the image can only look good when it is displayed on top of the light-gray or white background. But that didn't happen, the background was black. Now making the anti-aliasing pixels around the spyglass painfully obvious, they turned various shades of dark-gray depending on their alpha value and no longer blend with the white background of the document image. A very typical mishap when you use GDI functions, it does not like alpha.
You can doctor it with GDI+, ensuring that the background color is correct. But that's a fair amount of work and it still leaves you with the trouble of guessing at the original background color correctly.
Just really rather best to go back to whatever painting tool you used and fix the problem there. Quickest fix ought to be re-saving it as a 24bpp BMP image file, ymmv.

How to crop an Image using CvRect in Open CV.

I want to crop an image of 1176*640 to save the ROI of 1176*400 size. I am using the following snippet to acheive bit I am still getting the original image as output.
IplImage *CMyFunction::ROI(IplImage *pImage, CvRect ROI)
{
IplImage *mROI = cvCreateImage(cvGetSize(*pImage), IPL_DEPTH_8U, 1);
cvSetImageROI(pImage, rect_ROI);
cvCopy(pImage, mROI);
cvResetImageROI(pImage);
return mROI;
}
For cvCopy() the source and destination should be same size and type, that is the parameter like width, height, depth, and number of channel should be equal for both image. In your case you can change your code either like
IplImage *mROI = cvCreateImage(cvGetSize(pImage), pImage->depth, pImage->nChannels); //create dest with same size as source
cvSetImageROI(pImage, rect_ROI); //Set roi on source
cvSetImageROI(mROI, rect_ROI); //set roi on dest
cvCopy(pImage, mROI);
cvResetImageROI(pImage);
cvResetImageROI(mROI);
or
IplImage *mROI = cvCreateImage(cvSize(rect_ROI.width,rect_ROI.height), pImage->depth, pImage->nChannels); // create an image of size as rect
cvSetImageROI(pImage, rect_ROI); //set roi on source
cvCopy(pImage, mROI);
cvResetImageROI(pImage);
I understood that the pointer when leaves the function is no longer stable and declared a new IplImage* outside of the function and pass it as a parameter which proved to be efficient.
IplImage *CMyFunction::ROI(IplImage *pImage, CvRect ROI, IplImage* FinalImage)

Color Changing Sprites Cocos2d

I need my sprite to transition to one color to another and on and on... like blue tint then green then purple, but i cannot find any good actions for that and am wondering, should i use animations? or is there an incorporated action for this?
you can use CCTintTo action to change the color of the sprite
[sprite runAction:[CCTintTo actionWithDuration:2 red:255 green:0 blue:0]];
since i saw several questions about replacing pixel colours in sprites, and i did'nt see any good solution (all solution only tint the color, and none of them is able to change an array of colours without forcing you into creating multiple image layers which construct the final image you want, i.e: one layer for pans, other for show, other for shirt, another for hair colour... and it goes on - note that they do have their advantages like the ability to use accurate gradients)
my solution allows you to change array of colors, meaning you can have a single image with a known colors (you dont want any gradiants in this layer, only colours that you KNOW their values - PS this only applies to colors you intent to change, other pixels can have any colour you want)
if you need gradiants over the colours you change, create an additional image with only the shading and place it as a child of the sprite.
also be aware that i am super-new to cocos2d/x (3 days), and that this code is written for cocos2dx but can be ported to cocos2d easily.
also note that i didnt test it on android only on iOS, i am not sure how capable is android official gcc and how will it deal with the way i allocate _srcC and _dstC, but again, this is easily portable.
so here it goes:
cocos2d::CCSprite * spriteWithReplacedColors( const char * imgfilename, cocos2d::ccColor3B * srcColors, cocos2d::ccColor3B * dstColors, int numColors )
{
CCSprite *theSprite = NULL;
CCImage *theImage = new CCImage;
if( theImage->initWithImageFile( imgfilename ) )
{
//make a color array which is easier to work with
unsigned long _srcC [ numColors ];
unsigned long _dstC [ numColors ];
for( int c=0; c<numColors; c++ )
{
_srcC[c] = (srcColors[c].r << 0) | (srcColors[c].g << 8) | (srcColors[0].b << 16);
_dstC[c] = (dstColors[c].r << 0) | (dstColors[c].g << 8) | (dstColors[0].b << 16);
}
unsigned char * rawData = theImage->getData();
int width = theImage->getWidth();
int height = theImage->getHeight();
//replace the colors need replacing
unsigned int * b = (unsigned int *) rawData;
for( int pixel=0; pixel<width*height; pixel++ )
{
register unsigned int p = *b;
for( int c=0; c<numColors; c++ )
{
if( (p&0x00FFFFFF) == _srcC[c] )
{
*b = (p&0xFF000000) | _dstC[c];
break;
}
}
b++;
}
CCTexture2D *theTexture = new CCTexture2D();
if( theTexture->initWithData(rawData, kCCTexture2DPixelFormat_RGBA8888, width, height, CCSizeMake(width, height)) )
{
theSprite = CCSprite::spriteWithTexture(theTexture);
}
theTexture->release();
}
theImage->release();
return theSprite;
}
to use it just do the following:
ccColor3B src[] = { ccc3( 255,255,255 ), ccc3( 0, 0, 255 ) };
ccColor3B dst[] = { ccc3( 77,255,77 ), ccc3( 255, 0 0 ) };
//will change all whites to greens, and all blues to reds.
CCSprite * pSprite = spriteWithReplacedColors( "character_template.png", src, dst, sizeof(src)/sizeof(src[0]) );
of course if you need speed, you would create an extension for a sprite that create a pixel shader that does it hw accelerated at render time ;)
btw: this solution might cause some artefacts on the edges on some cases, so you can create a large image and scale it down, letting GL minimise the artefact.
you can also create "fix" layers with black outlines to hide the artefacts and place it on top etc.
also make sure you don't use these 'key' colors on the rest of the image you don't want the pixels changed.
also keep in mind that the fact that the alpha channel is not changed, and that if you use basic images with pure red/green/blue colors only, you can also optimize this function to eliminate all artefacts on edges automatically (and avoid in many cases, the need for an additional shade layer) and other cool stuff (multiplexing several images into a single bitmap - remember palette animation?)
enjoy ;)
In case someone wanted this for cocos2d-x here is the code:
somesprite->runAction(TintTo::create(float duration, Color3b &color));

Resources