I am developing a game bot and using opencv and I am trying to make it detect spikes.
The spikes look like this :
What I tried was using a FastFeatureDetector to highlight keypoints , the result was the following :
The spikes are horizontal and change colors.the operation is on a full 1920x1080 screen
So my thinking was to take one of the points and compare to all of the other points X's since I have no way of filtering the result and 6094 KeyPoints the operation took too long. (37136836 iterations).
Is there a way to filter FastFeatureDetector results or should I approach this in another way?
my code :
Point * findSpikes( Mat frame , int * num_spikes )
{
Point * ret = NULL;
int spikes_counter = 0;
Mat frame2;
cvtColor( frame , frame2 , CV_BGR2GRAY );
Ptr<FastFeatureDetector> myBlobDetector = FastFeatureDetector::create( );
vector<KeyPoint> myBlobs;
myBlobDetector->detect( frame2 , myBlobs );
HWND wnd = FindWindow( NULL , TEXT( "Andy" ) );
RECT andyRect;
GetWindowRect( wnd , &andyRect );
/*Mat blobimg;
drawKeypoints( frame2 , myBlobs , blobimg );*/
//imshow( "Blobs" , blobimg );
//waitKey( 1 );
printf( "Size of vectors : %d\n" , myBlobs.size( ) );
for ( vector<KeyPoint>::iterator blobIterator = myBlobs.begin( ); blobIterator != myBlobs.end( ); blobIterator++ )
{
#pragma region FilteringArea
//filtering keypoints
if ( blobIterator->pt.x > andyRect.right || blobIterator->pt.x < andyRect.left
|| blobIterator->pt.y > andyRect.bottom || blobIterator->pt.y < andyRect.top )
{
printf( "Filtered\n" );
continue;
}
#pragma endregion
for ( vector<KeyPoint>::iterator comparsion = myBlobs.begin( ); comparsion != myBlobs.end( ); comparsion++ )
{
//filtering keypoints
#pragma region FilteringRegion
if ( comparsion->pt.x > andyRect.right || comparsion->pt.x < andyRect.left
|| comparsion->pt.y > andyRect.bottom || comparsion->pt.y < andyRect.top )
{
printf( "Filtered\n" );
continue;
}
printf( "Processing\n" );
double diffX = abs( blobIterator->pt.x - comparsion->pt.x );
if ( diffX <= 5 )
{
spikes_counter++;
printf( "Spike added\n" );
ret = ( Point * ) realloc( ret , sizeof( Point ) * spikes_counter );
if ( !ret )
{
printf( "Memory error\n" );
ret = NULL;
}
ret[spikes_counter - 1].y = ( ( blobIterator->pt.y + comparsion->pt.y ) / 2 );
ret[spikes_counter - 1].x = blobIterator->pt.x;
break;
}
#pragma endregion
}
}
( *( num_spikes ) ) = spikes_counter;
return ret;//Modify later
}
I'm aware of the usage of realloc and printf in C++ I just don't like cout and new
Are the spikes actually different sizes and irregularly spaced in real life? In your image they are regularly spaced and identically sized and so once you know the coordinates of one point, you can calculate all of the rest by simply adding a fixed increment to the X coordinate.
If the spikes are irregularly spaced and potentially different heights, I'd suggest you might try :
Use Canny edge detector to find the boundary between the spikes and the background
For each X coord in this edge image, search a single column of the edge image using minMaxIdx to find the brightest point in that column
If the Y coordinate of that point is higher up the screen than the Y coordinate of the brightest point in the previous column then the previous column was a spike, save (X,Y) coords.
If a spike was found in step 3, keep skipping across columns until the brightest Y coordinate in a column is the same as in the previous column. Then repeat spike detection, otherwise keep searching for next spike
Considering the form of your spikes, I'd suggest template pattern mathcing. It seems keypoints are a rather indirect approach.
Related
I have two points top_left and bottom_right . To increase the area covered by the rectangle drawn from these points, I add/subtract sub values from them.
Point top_left -= Point( WIDTH_ADD, HEIGHT_ADD);
Point bottom_right += Point(WIDTH_ADD , HEIGHT_ADD );
Now I need to check whether they surpass the boundary of current frame (captured from camera).
If they do, I need to check and modify their values.
if ( top_left.x < 0 ) top_left.x = 0;
if ( bottom_right.x > frame.cols ) bottom_right.x = frame.cols;
if ( top_left.y < 0 ) top_left.y = 0;
if( bottom_right.y > frame.rows ) bottom_right.y = frame.rows;
Is there any fancy way of doing this in opencv ?
I don't know any, but even if there were, your code would probably be faster since you're skipping at least a function call to OpenCV.
I am calling next function inside class inside thread in loop ( capturing frames from camera and then processing them ) :
CvRect ImageProcessor::detectFaceInImage(const IplImage *inputImg) //
{
IplImage *detectImg;
CvMemStorage* storage = 0;
CvRect *rc = 0;
CvRect rect;
double count;
CvSeq* rects = 0;
int l,n;
detection_time = (double)cvGetTickCount();
detectImg = cvCloneImage(inputImg);
if(fastDetectMode)
{
faceCascade = (CvHaarClassifierCascade*)cvLoad(
faceCascadeFile[0].toAscii().data(),
0,
0,
0
);
if( !faceCascade )
{
QMessageBox mbox;
mbox.setIcon(QMessageBox::Information);
mbox.setText("Can't load haar cascade face detector 0");
mbox.setStandardButtons(QMessageBox::Ok);
mbox.exec();
if(detectImg)
cvReleaseImage(&detectImg);
return cvRect(-1,-1,-1,-1);
}
for(l=0;l<10;l++) //10 different search scale factors ( 10 )
{
storage = cvCreateMemStorage(1000000); //0
rects = cvHaarDetectObjects(
detectImg,
(CvHaarClassifierCascade*)faceCascade,
storage,
search_scale_factor[l],
minNeighborhood[1],
flags[0],
minFeatureSize[0]
);
if(rects->total>0)
{
for(n=0;n<rects->total;n++)
{
rc = (CvRect*)cvGetSeqElem( rects, n );
if((rc->height > 0.1*faceHeight) && (rc->width>0.1*faceWidth))
{
if(detectImg)
cvReleaseImage(&detectImg);
if(faceCascade)
cvFree(&faceCascade);
count = (double)cvGetTickCount();
detection_time = (double)((count - detection_time) /
(double)cvGetTickFrequency())/1000000;
rect = *rc;
cvReleaseMemStorage(&storage);
return rect;
}
}
}
if(storage)
cvReleaseMemStorage(&storage);
}
cvFree(&faceCascade);
}
//nothing found:
rect = cvRect(-1,-1,-1,-1);
count = (double)cvGetTickCount();
detection_time = (double)((count - detection_time) /
(double)cvGetTickFrequency())/1000000;
if(detectImg)
cvReleaseImage(&detectImg);
return rect;
}
I am expecting each time I call that function all necessary memory for detecting desired face region ( rectangle cvRect) in the input image is allocated and deallocated after function return. But what is happening when I run it is that there is some memory leak in function , another words , the RAM ( PC physical memory ) is constantly growing up when I call the function in a loop.
faceCascade is ImageProcessor class member as well as another not declared in the function variables.
Does anybody see what is wrong with memory creation/release ( allocation/deallocation ) in the function?
Why memory leak.
Thank you very much in advance for your help.
Paul
I've got a dialog that I'd basically like to implement as a texture viewer using DirectX. The source texture can either come from a file on-disk or from an arbitrary D3D texture/surface in memory. The window will be resizable, so I'll need to be able to scale its contents accordingly (preserving aspect ratio, while not necessary, would be useful to know).
What would be the best way to go about implementing the above?
IMHO the easiest way to do this is to create a quad (or two triangles) whose vertices contain the correct UV-coordinates. The XYZ coordinates you set to the viewing cube coordinates. This only works if the identity matrix is set as projection. You can use -1 to 1 on both X and Y axes.
EDIT: Here an example turorial:
http://www.mvps.org/directx/articles/splash_screen.htm
This is the code I use to preserve size and scaling for resizeable dialogue. My texture is held in a memory bitmap. I am sure you can adapt if you do not have a memory bitmap. The important bits is the way I determine the right scaling factor to preserve the aspect ratio for any client area size
CRect destRect( 0, 0, frameRect.Width(), frameRect.Height() );
if( txBitmapInfo.bmWidth <= frameRect.Width() && txBitmapInfo.bmHeight <= frameRect.Height() )
{
destRect.left = ( frameRect.Width() - txBitmapInfo.bmWidth ) / 2;
destRect.right = destRect.left + txBitmapInfo.bmWidth;
destRect.top = ( frameRect.Height() - txBitmapInfo.bmHeight ) / 2;
destRect.bottom = destRect.top + txBitmapInfo.bmHeight;
}
else
{
double hScale = static_cast<double>( frameRect.Width() ) / txBitmapInfo.bmWidth;
double vScale = static_cast<double>( frameRect.Height() ) / txBitmapInfo.bmHeight;
if( hScale < vScale )
{
int height = static_cast<int>( frameRect.Width() * ( static_cast<double>(txBitmapInfo.bmHeight) / txBitmapInfo.bmWidth ) );
destRect.top = ( frameRect.Height() - height ) / 2;
destRect.bottom = destRect.top + height;
}
else
{
int width = static_cast<int>( frameRect.Height() * ( static_cast<double>(txBitmapInfo.bmWidth) / txBitmapInfo.bmHeight ) );
destRect.left = ( frameRect.Width() - width ) / 2;
destRect.right = destRect.left + width;
}
}
Hope this helps!
I implemented a path simplification algorithm after reading the article here:
http://losingfight.com/blog/2011/05/30/how-to-implement-a-vector-brush/
It's worked for me pretty well for generating optimized level geometry for my game. But, I'm using it now to clean up a* pathfinding paths and it's got a weird edge case that fails miserably.
Here's a screenshot of it working - optimizing the path from red circle to the blue circle. The faint green line is the a* output, and the lighter whiteish line is the optimized path.
And here's a screenshot of it failing:
Here's my code. I adapted the ObjC code from the article to c++
Note: vec2fvec is a std::vector< vec2<float> >, and 'real' is just a typedef'd float.
void rdpSimplify( const vec2fvec &in, vec2fvec &out, real threshold )
{
if ( in.size() <= 2 )
{
out = in;
return;
}
//
// Find the vertex farthest from the line defined by the start and and of the path
//
real maxDist = 0;
size_t maxDistIndex = 0;
LineSegment line( in.front(), in.back() );
for ( vec2fvec::const_iterator it(in.begin()),end(in.end()); it != end; ++it )
{
real dist = line.distance( *it );
if ( dist > maxDist )
{
maxDist = dist;
maxDistIndex = it - in.begin();
}
}
//
// If the farhtest vertex is greater than our threshold, we need to
// partition and optimize left and right separately
//
if ( maxDist > threshold )
{
//
// Partition 'in' into left and right subvectors, and optimize them
//
vec2fvec left( maxDistIndex+1 ),
right( in.size() - maxDistIndex ),
leftSimplified,
rightSimplified;
std::copy( in.begin(), in.begin() + maxDistIndex + 1, left.begin() );
std::copy( in.begin() + maxDistIndex, in.end(), right.begin() );
rdpSimplify(left, leftSimplified, threshold );
rdpSimplify(right, rightSimplified, threshold );
//
// Stitch optimized left and right into 'out'
//
out.resize( leftSimplified.size() + rightSimplified.size() - 1 );
std::copy( leftSimplified.begin(), leftSimplified.end(), out.begin());
std::copy( rightSimplified.begin() + 1, rightSimplified.end(), out.begin() + leftSimplified.size() );
}
else
{
out.push_back( line.a );
out.push_back( line.b );
}
}
I'm really at a loss as to what's going wrong. My spidey sense says it's in the std::copy calls... I must be copying garbage in some circumstances.
EDIT:
I've rewritten the algorithm dropping any use of iterators and std::copy, and the like. It still fails in the exact same way.
void rdpSimplify( const vec2fvec &in, vec2fvec &out, real threshold )
{
if ( in.size() <= 2 )
{
out = in;
return;
}
//
// Find the vertex farthest from the line defined by the start and and of the path
//
real maxDist = 0;
size_t maxDistIndex = 0;
LineSegment line( in.front(), in.back() );
for ( size_t i = 0, N = in.size(); i < N; i++ )
{
real dist = line.distance( in[i] );
if ( dist > maxDist )
{
maxDist = dist;
maxDistIndex = i;
}
}
//
// If the farthest vertex is greater than our threshold, we need to
// partition and optimize left and right separately
//
if ( maxDist > threshold )
{
//
// Partition 'in' into left and right subvectors, and optimize them
//
vec2fvec left, right, leftSimplified, rightSimplified;
for ( size_t i = 0; i < maxDistIndex + 1; i++ ) left.push_back( in[i] );
for ( size_t i = maxDistIndex; i < in.size(); i++ ) right.push_back( in[i] );
rdpSimplify(left, leftSimplified, threshold );
rdpSimplify(right, rightSimplified, threshold );
//
// Stitch optimized left and right into 'out'
//
out.clear();
for ( size_t i = 0, N = leftSimplified.size(); i < N; i++ ) out.push_back(leftSimplified[i]);
for ( size_t i = 1, N = rightSimplified.size(); i < N; i++ ) out.push_back( rightSimplified[i] );
}
else
{
out.push_back( line.a );
out.push_back( line.b );
}
}
I can't find any faults in your code.
Some things to try:
Add some debug print statements to check what maxDist is in the failing case. It should be really low, but if it comes out high then you know there's a problem with your line segment distance code.
Check that the path you are seeing actually matches the path that your algorithm returns. If not then perhaps there is something wrong with your path rendering? Maybe a bug when the path only has two points?
Check that your input path is what you expect it to be by printing out all its coordinates at the start of the algorithm.
It shouldn't take too long to find the cause of the problem if you just investigate a little. After a few minutes, staring at code is a very poor way to debug.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
How can someone use Qt for image processing? Are there libraries or plugins for Qt for this purpose?
Thanks.
Qt is rather meant for developing graphical user interfaces (GUIs). However, it comes with a lot of supplementary libraries, including one dedicated to image processing. However, if you want to get serious, I would recommend a dedicated library such as OpenCV.
I did use Qt for GUI plus LTIlib for image processing.
Qt itself won't be very helpful for processing any image, but there are a couple of independent libraries that you can use best fitting your needs. Bear in mind that Qt is essentially meant to be a GUI framework. It is very very good, if not the best, to make windows, buttons, tree views, etc. but don't expect it to be so comprehensive that can do everything.
Please let us to know more preciselly what you mean when you say "image processing".
It is a vast reign with hundreds or thousands of possible goals and approaches...
EDIT:
Here is a small excerpt or what I used to do with Qt+LTI.
See LTI documentation for all operators available. I used to do convolutions, self-correlations, basic erosion/dilation and a lot more.
#include <ltiDilation.h>
#include <ltiErosion.h>
#include <ltiBinaryKernels.h>
#include <ltiFastRelabeling.h>
#include <ltiLabelAdjacencyMap.h>
void QLTIDialog::init()
{
viewLayout = new QGridLayout( frmView, 1, 1, 4, 4, "viewLayout" );
view= new QImageLabel( frmView, "view" );
viewLayout->addWidget( view, 0, 0 );
frmView->setUpdatesEnabled( false );
view->image( &qimg );
}
void QLTIDialog::btnOpen_clicked()
{
QString fn= QFileDialog::getOpenFileName(
"",
tr( "All files (*.*)" ),
this,
tr( "Open image" ),
tr( "Select image file" ) );
if ( !fn.isEmpty( ) )
{
if ( !qimg.load( fn ) )
{
QMessageBox::critical( this, tr( "Fatal error" ),
QString( tr( "Unable to open %1" ) ).arg( fn ),
tr( "Exit" ) );
return;
}
view->update( );
setCaption( fn );
}
}
void QLTIDialog::btnProcess_clicked()
{
lti::image img;
lti::channel8 tmp0,
h, s, v;
// Taking QImage data, as in the wiki.
img.useExternData( qimg.width( ), qimg.height( ), ( lti::rgbPixel * )qimg.bits( ) );
// Converting to HSV gives-me best results, but it can be left out.
lti::splitImageToHSV hsv;
hsv.apply( img, h, s, v );
// I do some manipulation over the channels to achieve my objects positions.
lti::maskFunctor< lti::channel8::value_type > masker;
masker.invert( v, tmp0 );
masker.algebraicSum( s, tmp0 );
// Show the resulting processed image (ilustrative)...
QLTIDialog *dh= new QLTIDialog;
dh->showImage( tmp0 );
// Apply relabeling (example). Any other operator can be used.
lti::fastRelabeling::parameters flPar;
flPar.sortSize= true;
flPar.minimumObjectSize= 25;
flPar.fourNeighborhood= true;
flPar.minThreshold= 40;
lti::fastRelabeling fr( flPar );
fr.apply( tmp0 );
lti::image imgLam;
lti::labelAdjacencyMap lam;
lam.apply( tmp0, imgLam );
// By hand copy to QImage.
lti::image::iterator iit= imgLam.begin( );
lti::rgbPixel *pix= ( lti::rgbPixel * )qimg.bits( );
for ( ; iit != imgLam.end( ); ++iit, ++pix )
*pix= *iit;
view->update( );
}
void QLTIDialog::showImage( lti::image &img )
{
qimg= QImage( reinterpret_cast< uchar * >( &( *img.begin( ) ) ),
img.rows( ), img.columns( ), 32, ( QRgb * )NULL,
0, QImage::LittleEndian ).copy( );
QDialog::show( );
}
void QLTIDialog::showImage( lti::channel8 &ch )
{
lti::image img;
img.castFrom( ch );
qimg= QImage( reinterpret_cast< uchar * >( &( *img.begin( ) ) ),
img.rows( ), img.columns( ), 32, ( QRgb * )NULL,
0, QImage::LittleEndian ).copy( );
QDialog::show( );
}
EDIT Again:
I found another sample that may be more interesting to you...
lti::image img;
lti::channel8 chnl8( false, imgH, imgW ), h, s, v;
// Pass image data to LTI.
img.useExternData( imgH, imgW, ( lti::rgbPixel * )pixels );
// I got better results in HSV for my images.
lti::splitImageToHSV hsv;
hsv.apply( img, h, s, v );
// Segmentation.
lti::channel8::iterator it= chnl8.begin( );
lti::channel8::iterator hit= h.begin( ),
sit= s.begin( ),
vit= v.begin( );
for ( ; it != chnl8.end( ); ++it, ++hit, ++sit, ++vit )
{
int tmp= *sit * 2;
tmp-= *hit - 320 + *vit;
*it= ( *hit > 40 && tmp > 460 ? 1 : 0 );
}
// Distinguish connected objects.
lti::imatrix objs;
std::vector< lti::geometricFeatureGroup0 > objF;
lti::geometricFeaturesFromMask::parameters gfPar;
gfPar.merge= true; // Join close objects.
gfPar.minimumDistance= lti::point( 24, 24 );
gfPar.minimumMergedObjectSize= 2; // Exclude small ones.
gfPar.nBest= 800; // Limit no. of objects.
lti::geometricFeaturesFromMask gf( gfPar );
gf.apply( chnl8, objs, objF );
points.clear( );
for( std::vector< lti::geometricFeatureGroup0 >::const_iterator gfg0= objF.begin( );
gfg0 != objF.end( ); ++gfg0 )
points.push_back( Point( gfg0->cog.x, gfg0->cog.y ) );
The rest is like the first example.
Hope it helps.
Image processing is a rather generic term. Have a look at VTK and ITK from Kitware. Also Freemat (a Matlab clone) is based on Qt. Qt is popular among quantitative scientists, I expect that there quite a few Qt-based imaging libraries and products.
I use QT for image Processing. I use OpenCV then I convert the OpenCV Mat into a QImage, then I display it in a label on the UI.
Thank you