Related
I have this free indicator is the name is FiboPiv_v2.mq4.
It's a tool I use with good result in trading scalping. I set normally the alert by hand, but I see that the code is open and so I'd like to do a modification but I'm quite newbie in programming MQL4.
I would like to add a pop-up and sound that says something like "AUDUSD has reached S1".
Code of the indicator:
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
ObjectDelete("S1");
ObjectDelete("S2");
ObjectDelete("S3");
ObjectDelete("R1");
ObjectDelete("R2");
ObjectDelete("R3");
ObjectDelete("PIVIOT");
ObjectDelete("Support 1");
ObjectDelete("Support 2");
ObjectDelete("Support 3");
ObjectDelete("Piviot level");
ObjectDelete("Resistance 1");
ObjectDelete("Resistance 2");
ObjectDelete("Resistance 3");
Comment(" ");
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
double rates[1][6],yesterday_close,yesterday_high,yesterday_low;
ArrayCopyRates(rates,Symbol(),PERIOD_D1);
//----
if(DayOfWeek()==1)
{
if(TimeDayOfWeek(iTime(Symbol(),PERIOD_D1,1))==5)
{
yesterday_close= rates[1][4];
yesterday_high = rates[1][3];
yesterday_low=rates[1][2];
}
else
{
for(int d=5;d>=0;d--)
{
if(TimeDayOfWeek(iTime(Symbol(),PERIOD_D1,d))==5)
{
yesterday_close= rates[d][4];
yesterday_high = rates[d][3];
yesterday_low=rates[d][2];
}
}
}
}
else
{
yesterday_close= rates[1][4];
yesterday_high = rates[1][3];
yesterday_low=rates[1][2];
}
//---- Calculate Pivots
Comment("\nYesterday quotations:\nH ",yesterday_high,"\nL
",yesterday_low,"\nC ",yesterday_close);
double R=yesterday_high-yesterday_low;//range
double p=(yesterday_high+yesterday_low+yesterday_close)/3;// Standard Pivot
double r3 = p + (R * 1.000);
double r2 = p + (R * 0.618);
double r1 = p + (R * 0.382);
double s1 = p - (R * 0.382);
double s2 = p - (R * 0.618);
double s3 = p - (R * 1.000);
//----
drawLine(r3,"R3",Lime,0);
drawLabel("Resistance 3",r3,Lime);
drawLine(r2,"R2",Green,0);
drawLabel("Resistance 2",r2,Green);
drawLine(r1,"R1",DarkGreen,0);
drawLabel("Resistance 1",r1,DarkGreen);
drawLine(p,"PIVIOT",Blue,1);
drawLabel("Piviot level",p,Blue);
drawLine(s1,"S1",Maroon,0);
drawLabel("Support 1",s1,Maroon);
drawLine(s2,"S2",Crimson,0);
drawLabel("Support 2",s2,Crimson);
drawLine(s3,"S3",Red,0);
drawLabel("Support 3",s3,Red);
//----
return(0);
}
//+------------------------------------------------------------------+
void drawLabel(string name,double lvl,color Color)
{
if(ObjectFind(name)!=0)
{
if(Bars<10) return;
ObjectCreate(name,OBJ_TEXT,0,Time[10],lvl);
ObjectSetText(name,name,8,"Arial",EMPTY);
ObjectSet(name,OBJPROP_COLOR,Color);
}
else
{
if(Bars<10) return;
ObjectMove(name,0,Time[10],lvl);
}
}
//----
void drawLine(double lvl,string name,color Col,int type)
{
if(ObjectFind(name)!=0)
{
ObjectCreate(name,OBJ_HLINE,0,Time[0],lvl,Time[0],lvl);
if(type==1)
ObjectSet(name,OBJPROP_STYLE,STYLE_SOLID);
else
ObjectSet(name,OBJPROP_STYLE,STYLE_DOT);
ObjectSet(name,OBJPROP_COLOR,Col);
ObjectSet(name,OBJPROP_WIDTH,1);
}
else
{
ObjectDelete(name);
ObjectCreate(name,OBJ_HLINE,0,Time[0],lvl,Time[0],lvl);
if(type==1)
ObjectSet(name,OBJPROP_STYLE,STYLE_SOLID);
else
ObjectSet(name,OBJPROP_STYLE,STYLE_DOT);
ObjectSet(name,OBJPROP_COLOR,Col);
ObjectSet(name,OBJPROP_WIDTH,1);
}
}
//+--------------------------------------------------------------------+
First:
Forget to have an Alert() call inside an Indicator type of MQL4-code. For details ref. below + MQL4 Documentation on such and similarly forbidden blocking calls.
Next :The original code was awfully inefficient
( see details in documentation on New-MQL4.56789, in 2018/Q2 still runs all ( indeed ALL platform's instances of concurrently operated CustomIndicator + Indicators inside one, single, solo, blocking-vulnerable, SPOF-thread (!!) )
A sort of efficiency-repaired code that does not "shaking all trees" bottom up per each QUOTE-arrival, that yet performs all the necessary updates and shows the beeping-alarm scheme:
#property indicator_chart_window
double R, r3, r2, r1, p, s1, s2, s3; // SEMI-GLOBALs for easy runPriceCHECKs()
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
static int aLastVisitedBAR = EMPTY; // INIT
if ( aLastVisitedBAR == iBars( _Symbol, PERIOD_D1 ) ) // TEST:
{ runPriceCHECKs(); // Check Price v/s PIVOT levels
return( 0 ); // but PIVOTs never change during the same day ... so JIT/RET--^
}
else aLastVisitedBAR == iBars( _Symbol, PERIOD_D1 ); // SYNC & RE-CALC:
double rates[][6], yesterday_close,
yesterday_high,
yesterday_low;
ArrayCopyRates( rates,
_Symbol,
PERIOD_D1
);
//----
if ( DayOfWeek() == 1 )
{
if ( TimeDayOfWeek( iTime( _Symbol, PERIOD_D1, 1 ) ) == 5 )
{
yesterday_close = rates[1][4];
yesterday_high = rates[1][3];
yesterday_low = rates[1][2];
}
else
{
for ( int d = 5; d >= 0; d-- )
{
if ( TimeDayOfWeek( iTime( _Symbol, PERIOD_D1, d ) ) == 5 )
{
yesterday_close = rates[d][4];
yesterday_high = rates[d][3];
yesterday_low = rates[d][2];
}
}
}
}
else
{
yesterday_close = rates[1][4];
yesterday_high = rates[1][3];
yesterday_low = rates[1][2];
}
//---- Calculate Pivots
Comment( "\nYesterday quotations:\nH ",
yesterday_high, "\nL ",
yesterday_low, "\nC ",
yesterday_close
);
R = yesterday_high - yesterday_low; // a Day range
p = ( yesterday_high + yesterday_low + yesterday_close ) /3;// a Standard Pivot
r3 = p + ( R * 1.000 ); drawLine( r3, "R3", clrLime, 0 ); drawLabel( "Resistance 3", r3, clrLime );
r2 = p + ( R * 0.618 ); drawLine( r2, "R2", clrGreen, 0 ); drawLabel( "Resistance 2", r2, clrGreen );
r1 = p + ( R * 0.382 ); drawLine( r1, "R1", clrDarkGreen, 0 ); drawLabel( "Resistance 1", r1, clrDarkGreen );
drawLine( p, "PIVOT", clrBlue, 1 ); drawLabel( "Pivot level", p, clrBlue );
s1 = p - ( R * 0.382 ); drawLine( s1, "S1", clrMaroon, 0 ); drawLabel( "Support 1", s1, clrMaroon );
s2 = p - ( R * 0.618 ); drawLine( s2, "S2", clrCrimson, 0 ); drawLabel( "Support 2", s2, clrCrimson );
s3 = p - ( R * 1.000 ); drawLine( s3, "S3", clrRed, 0 ); drawLabel( "Support 3", s3, clrRed );
//----
runPriceCHECKs(); // Check Price v/s PIVOT levels
//----
return( 0 );
}
//+------------------------------------------------------------------+
//| drawLabel( string name, double lvl, color Color ) |
//+------------------------------------------------------------------+
void drawLabel( string name, double lvl, color Color )
{
if ( Bars < 10 ) return;
if ( ObjectFind( name ) == 0 ) ObjectMove( name, 0, Time[10], lvl );
else
{ ObjectCreate( name, OBJ_TEXT, 0, Time[10], lvl );
ObjectSet( name, OBJPROP_COLOR, Color );
ObjectSetText( name, name, 8, "Arial", EMPTY );
}
}
//+------------------------------------------------------------------+
//| drawLine( double lvl, string name, color Col, int type ) |
//+------------------------------------------------------------------+
void drawLine( double lvl, string name, color Col, int type )
{
if ( ObjectFind( name ) == 0 )
ObjectDelete( name );
ObjectCreate( name, OBJ_HLINE, 0, Time[0], lvl,
Time[0], lvl );
ObjectSet( name, OBJPROP_COLOR, Col );
ObjectSet( name, OBJPROP_WIDTH, 1 );
ObjectSet( name, OBJPROP_STYLE, ( type == 1 ) ? STYLE_SOLID : STYLE_DOT );
}
//+------------------------------------------------------------------+
//| runPriceCHECKs() |
//+------------------------------------------------------------------+
void runPriceCHECKs()
{
#define DEF_PROXIMITY_TRESHOLD_R3 ( 15 * Point )
#define DEF_PROXIMITY_TRESHOLD_R2 ( 10 * Point )
#define DEF_PROXIMITY_TRESHOLD_R1 ( 5 * Point )
#define DEF_PROXIMITY_TRESHOLD_P ( 2 * Point )
#define DEF_PROXIMITY_TRESHOLD_S1 ( 5 * Point )
#define DEF_PROXIMITY_TRESHOLD_S2 ( 10 * Point )
#define DEF_PROXIMITY_TRESHOLD_S3 ( 15 * Point )
if ( MathAbs( r3 - Close ) <= DEF_PROXIMITY_TRESHOLD_R3 )
...
PlaySound( aFileNAME_WAV_R3 ); // The file must be located in terminal_directory\Sounds or its sub-directory. Only WAV files are played.
// Sleep( 250 ); // 250 [ms] AS A LAST RESORT, BETTER MAKE .WAV CUT-SHORT NOT TO LAST LONGER BY ITSELF
// PlaySound( NULL );
return;
if ( MathAbs( r2 - Close ) <= DEF_PROXIMITY_TRESHOLD_R2 )
...
return;
if ( MathAbs( r1 - Close ) <= DEF_PROXIMITY_TRESHOLD_R1 )
...
return;
if ( MathAbs( p - Close ) <= DEF_PROXIMITY_TRESHOLD_P )
...
return;
if ( MathAbs( s1 - Close ) <= DEF_PROXIMITY_TRESHOLD_S1 )
...
return;
if ( MathAbs( s2 - Close ) <= DEF_PROXIMITY_TRESHOLD_S2 )
...
return;
if ( MathAbs( s3 - Close ) <= DEF_PROXIMITY_TRESHOLD_S3 )
...
return;
// nop
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{ return( 0 );
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
ObjectDelete( "S1" );
ObjectDelete( "S2" );
ObjectDelete( "S3" );
ObjectDelete( "R1" );
ObjectDelete( "R2" );
ObjectDelete( "R3" );
ObjectDelete( "PIVOT" );
ObjectDelete( "Support 1" );
ObjectDelete( "Support 2" );
ObjectDelete( "Support 3" );
ObjectDelete( "Piviot level" );
ObjectDelete( "Resistance 1" );
ObjectDelete( "Resistance 2" );
ObjectDelete( "Resistance 3" );
Comment( ":o)" );
//----
return( 0 );
}
//+------------------------------------------------------------------+
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.
I am trying to implement a function which calculates the weightings and abscissae for the Gauss-Laguerre numerical integration method using C++AMP to parallelize the process and when running it I am getting a DXGI_ERROR_DEVICE_HUNG error.
This is my helper method for computing the logarithm of the gamma function on the GPU:
template <typename T>
T gammaln_fast( T tArg ) restrict( amp )
{
const T tCoefficients[] = { T( 57.1562356658629235f ), T( -59.5979603554754912f ),
T( 14.1360979747417471f ), T( -0.491913816097620199f ), T( 0.339946499848118887E-4f ),
T( 0.465236289270485756E-4f ), T( -0.983744753048795646E-4f ), T( 0.158088703224912494E-3f ),
T( -0.210264441724104883E-3f ), T( 0.217439618115212643E-3f ), T( -0.164318106536763890E-3f ),
T( 0.844182239838527433E-4f ), T( -0.261908384015814087E-4f ), T( 0.386991826595316234E-5f ) };
T y = tArg, tTemp = tArg + T( 5.2421875f );
tTemp = (tArg + T( 0.5f )) * concurrency::fast_math::log( tTemp ) - tTemp;
T tSer = T( 0.999999999999997092f );
for( std::size_t s = 0; s < (sizeof( tCoefficients ) / sizeof( T )); ++s )
{
tSer += tCoefficients[s] / ++y;
}
return tTemp + concurrency::fast_math::log( T( 2.5066282746310005f ) * tSer / tArg );
}
And here is my function which computes the weights and abscissae:
template <typename T>
ArrayPair<T> CalculateGaussLaguerreWeights_fast( const T tExponent, const std::size_t sNumPoints, T tEps = std::numeric_limits<T>::epsilon() )
{
static_assert(std::is_floating_point<T>::value, "You can only instantiate this function with a floating point data type");
static_assert(!std::is_same<T, long double>::value, "You can not instantiate this function with long double type"); // The long double type is not currently supported by C++AMP
T tCurrentGuess, tFatherGuess, tGrandFatherGuess;
std::vector<T> vecInitialGuesses( sNumPoints );
for( std::size_t s = 0; s < sNumPoints; ++s )
{
if( s == 0 )
{
tCurrentGuess = (T( 1.0f ) + tExponent) * (T( 3.0f ) + T( 0.92f ) * tExponent) / (T( 1.0f ) + T( 2.4f ) * sNumPoints + T( 1.8f ) * tExponent);
}
else if( s == 1 )
{
tFatherGuess = tCurrentGuess;
tCurrentGuess += (T( 15.0f ) + T( 6.25f ) * tExponent) / (T( 1.0f ) + T( 0.9f ) * tExponent + T( 2.5f ) * sNumPoints);
}
else
{
tGrandFatherGuess = tFatherGuess;
tFatherGuess = tCurrentGuess;
std::size_t sDec = s - 1U;
tCurrentGuess += ((T( 1.0f ) + T( 2.55f ) * sDec) / (T( 1.9f ) * sDec) + T( 1.26f ) * sDec * tExponent
/ (T( 1.0f ) + T( 3.5f ) * sDec)) * (tCurrentGuess - tGrandFatherGuess) / (T( 1.0f ) + T( 0.3f ) * tExponent);
}
vecInitialGuesses[s] = tCurrentGuess;
}
concurrency::array<T> arrWeights( sNumPoints ), arrAbsciasses( sNumPoints, std::begin(vecInitialGuesses) );
try {
concurrency::parallel_for_each( arrAbsciasses.extent, [=, &arrAbsciasses, &arrWeights]( concurrency::index<1> index ) restrict( amp ) {
T tVal = arrAbsciasses[index], tIntermediate;
T tPolynomial1 = T( 1.0f ), tPolynomial2 = T( 0.0f ), tPolynomial3, tDerivative;
std::size_t sIterationNum = 0;
do {
tPolynomial1 = T( 1.0f ), tPolynomial2 = T( 0.0f );
for( std::size_t s = 0; s < sNumPoints; ++s )
{
tPolynomial3 = tPolynomial2;
tPolynomial2 = tPolynomial1;
tPolynomial1 = ((2 * s + 1 + tExponent - tVal) * tPolynomial2 - (s + tExponent) * tPolynomial3) / (s + 1);
}
tDerivative = (sNumPoints * tPolynomial1 - (sNumPoints + tExponent) * tPolynomial2) / tVal;
tIntermediate = tVal;
tVal = tIntermediate - tPolynomial1 / tDerivative;
++sIterationNum;
} while( concurrency::fast_math::fabs( tVal - tIntermediate ) > tEps || sIterationNum < 10 );
arrAbsciasses[index] = tVal;
arrWeights[index] = -concurrency::fast_math::exp( gammaln_fast( tExponent + sNumPoints ) - gammaln_fast( T( sNumPoints ) ) ) / (tDerivative * sNumPoints * tPolynomial2);
} );
}
catch( concurrency::runtime_exception& e )
{
std::cerr << "Runtime error, code: " << e.get_error_code() << "; message: " << e.what() << std::endl;
}
return std::make_pair( std::move( arrAbsciasses ), std::move( arrWeights ) );
}
And here is the full trace from the debug console:
D3D11: Removing Device.
D3D11 ERROR: ID3D11Device::RemoveDevice: Device removal has been triggered for the following reason (DXGI_ERROR_DEVICE_HUNG: The Device took an unreasonable amount of time to execute its commands, or the hardware crashed/hung. As a result, the TDR (Timeout Detection and Recovery) mechanism has been triggered. The current Device Context was executing commands when the hang occurred. The application may want to respawn and fallback to less aggressive use of the display hardware). [ EXECUTION ERROR #378: DEVICE_REMOVAL_PROCESS_AT_FAULT]
D3D11 ERROR: ID3D11DeviceContext::Map: Returning DXGI_ERROR_DEVICE_REMOVED, when a Resource was trying to be mapped with READ or READWRITE. [ RESOURCE_MANIPULATION ERROR #2097214: RESOURCE_MAP_DEVICEREMOVED_RETURN]
My apologies for not being able to produce a small reproducible example; I hope that this is still an acceptable question, as I am unable to solve this by myself.
When using DirectCompute, the main challenge is to write computations that do not run afoul of the Direct3D automatic 'GPU hang' detection timeout. By default, the system assumes if a shader is taking more than a few seconds, the GPU is actually hung. This heuristic works for visual shaders, but you can easily create a DirectCompute shader that takes a long time to complete.
The solution is to disable the timeout detection. You can do this by creating the Direct3D 11 device with D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT See Disabling TDR on Windows 8 for your C++ AMP algorithms blog post. The main thing to remember is that D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT requires the DirectX 11.1 or later runtime which is included with Windows 8.x and can be installed on Windows 7 Service Pack 1 with KB2670838. See DirectX 11.1 and Windows 7, DirectX 11.1 and Windows 7 Update, and MSDN for some caveats of using KB2670838.
I'm trying to use a library I found for triangulations, and I'm getting a strange error. When I compile everything, I get the following errors:
'_trytoadd' is ambiguous ' Candidates are: void _trytoadd(Se<SeDcdtVertex,SeDcdtEdge,SeDcdtFace>
*, Se<SeDcdtVertex,SeDcdtEdge,SeDcdtFace> *, int, const GsVec2 &, const GsVec2 &, const GsVec2
&) '
I'm getting this error for _cantpass, _try to add and _ptreeaddent functions, but they are all defined and called properly in this .cpp file. Any idea what's wrong? Here's the code for the class in question:
/*=======================================================================
Copyright 2010 Marcelo Kallmann. All Rights Reserved.
This software is distributed for noncommercial use only, without
any warranties, and provided that all copies contain the full copyright
notice licence.txt located at the base folder of the distribution.
=======================================================================*/
# include <math.h>
# include <stdlib.h>
# include "gs_geo2.h"
# include "se_lct.h"
# include "se_triangulator_internal.h"
# define GS_TRACE_ONLY_LINES
//# define GS_USE_TRACE1 // main search method
//# define GS_USE_TRACE2 // search expansion
//# define GS_USE_TRACE3
# include "gs_trace.h"
//================================================================================
//========================== search path tree ====================================
//================================================================================
// nen/nex are the entrance/exit edges of the node being expanded, which is already in the search tree
// en/ex are the entrance/exit edge of the current traversal being evaluated for expansion
// (p1,p2) are en coordinates
bool SeLct::_canpass ( SeDcdtSymEdge* nen, SeDcdtSymEdge* nex, SeDcdtSymEdge* en, SeDcdtSymEdge* ex,
const GsPnt2& p1, const GsPnt2& p2, const GsPnt2& p3, float r, float d2 )
{
// check if can traverse en/ex traversal:
if ( _man->is_constrained(ex->edg()) ) return false;
// test if next triangle being tested has been already visited:
if ( _mesh->marked(en->fac()) ) return false;
if ( en->nxt()==ex ) // bot
{
if ( _pre_clearance )
{ float cl = ex->edg()->cl(ex);
if ( cl<d2 ) return false;
}
else
{ if ( dist2(p2,p3)<d2 ) return false;
if ( !_sector_clear(ex->nxt(),d2,p2,p3,p1) ) return false;
}
if ( nex->fac()==_fi && nex->nxt()==nen ) // top->bot departure transition
{ if ( !_local_transition_free(ex,en,d2,_xi,_yi) ) return false;
}
}
else // top
{
if ( _pre_clearance )
{ float cl = en->edg()->cl(en);
if ( cl<d2 ) return false;
}
else
{ if ( dist2(p3,p1)<d2 ) return false;
if ( !_sector_clear(en->nxt(),d2,p1,p2,p3) ) return false;
}
if ( nex->fac()==_fi && nen->nxt()==nex ) // bot->top departure transition
{ if ( !_local_transition_free(ex,en,d2,_xi,_yi) ) return false;
}
}
return true;
}
// en is the entrance edge, ex the exit edge, (p1,p2) are en coordinates
void SeLct::_trytoadd ( SeDcdtSymEdge* en, SeDcdtSymEdge* ex, int mi, const GsPnt2& p1, const GsPnt2& p2, const GsPnt2& p3 )
{
// verify if it is passable:
PathNode& n = _ptree->nodes[mi];
if ( !_canpass ( (SeDcdtSymEdge*)n.en, (SeDcdtSymEdge*)n.ex, en, ex, p1, p2, p3, _ptree->radius, _ptree->diam2 ) ) return;
// ok it is passable, compute cost:
double x, y;
if ( en->nxt()==ex )
_getcostpoint ( &n, n.x, n.y, p2.x, p2.y, p3.x, p3.y, x, y, _ptree->radius ); // bot
else
_getcostpoint ( &n, n.x, n.y, p3.x, p3.y, p1.x, p1.y, x, y, _ptree->radius ); // top
// insert:
# define PTDIST(a,b,c,d) float(sqrt(gs_dist2(a,b,c,d)))
_ptree->add_child ( mi, en, ex, n.ncost+PTDIST(n.x,n.y,x,y), PTDIST(x,y,_xg,_yg), x,y ); // A* heuristic
# undef PTDIST
}
# define ExpansionNotFinished -1
# define ExpansionBlocked -2
int SeLct::_expand_lowest_cost_leaf ()
{
int min_i;
if ( _ptree->leafs.size()>_maxfronts ) _maxfronts=_ptree->leafs.size();
min_i = _ptree->lowest_cost_leaf ();
GS_TRACE2 ( "Expanding leaf: "<<min_i );
if ( min_i<0 ) return ExpansionBlocked; // no more leafs: path could not be found!
// attention: array references may be invalidated due array reallocation during insertion
SeDcdtSymEdge* s = (SeDcdtSymEdge*) _ptree->nodes[min_i].ex->sym();
SeDcdtSymEdge* sn = s->nxt();
SeDcdtSymEdge* sp = sn->nxt();
const GsPnt2& p1 = s->vtx()->p; // note: s is in the triangle to expand
const GsPnt2& p2 = sn->vtx()->p;
const GsPnt2& p3 = sp->vtx()->p;
float d2 = _ptree->diam2;
// test if next triangle contains goal point:
if ( gs_in_triangle(p1.x,p1.y,p2.x,p2.y,p3.x,p3.y,_xg,_yg) ) // reached goal triangle !
{ GS_TRACE1 ( "Goal triangle reached..." );
double r = _ptree->radius;
if ( !pt2circfree(this,s,_xg,_yg,r) ) // we do not know if the goal location is valid, so test it now
{ GS_TRACE1 ( "Goal location is invalid." );
return ExpansionBlocked;
}
GS_TRACE1 ( "Goal location valid." );
GS_TRACE1 ( "Analyzing arrival..." );
SeDcdtSymEdge* nen = (SeDcdtSymEdge*)_ptree->nodes[min_i].en;
SeDcdtSymEdge* nex = (SeDcdtSymEdge*)_ptree->nodes[min_i].ex;
_analyze_arrival ( s, 3, r, d2, nen, nex );
if ( _ent[3].type==EntBlocked )
{ if ( (sn->edg()->is_constrained()||dist2(p2,p3)<d2) &&
(sp->edg()->is_constrained()||dist2(p3,p1)<d2) )
{ GS_TRACE1 ( "Arrival blocked from all possible entries." );
return ExpansionBlocked;
}
else
{ GS_TRACE1 ( "Arrival is blocked, but search can continue..." );
// at this point the arrival is not valid but the search will continue, and
// note that the arrival triangle may still be used as passage so we let
// the expansion tests in _trytoadd() proceed.
}
}
else
{ GS_TRACE1 ( "Arrival tests passed." );
GS_TRACE1 ( "Arrival is valid " << (_ent[3].type==EntTrivial?"and trivial.":"but non trivial.") );
return min_i; // FOUND!
}
}
int nsize = _ptree->nodes.size();
_trytoadd ( s, sn, min_i, p1, p2, p3 ); // bot
_trytoadd ( s, sp, min_i, p1, p2, p3 ); // top
if ( _ptree->nodes.size()>nsize ) _mesh->mark ( s->fac() ); // only mark traversed faces
if (_searchcb) _searchcb(_sudata);
return ExpansionNotFinished; // continue the expansion
}
void SeLct::_ptreeaddent ( SeDcdtSymEdge* s, bool top, bool edge )
{
const GsPnt2& p1 = s->vtx()->p;
const GsPnt2& p2 = s->nvtx()->p;
double x, y;
if ( edge )
{ x=_xi; y=_yi; }
else
{ _getcostpoint ( 0, _xi, _yi, p1.x, p1.y, p2.x, p2.y, x, y, _ptree->radius ); }
// insert:
# define PTDIST(a,b,c,d) (float)sqrt(gs_dist2(a,b,c,d))
_ptree->add_child ( -1, top? s->nxt():s->nxn(), s, PTDIST(_xi,_yi,x,y), PTDIST(x,y,_xg,_yg), x, y );
# undef PTDIST
}
//================================================================================
//============================== search path =====================================
//================================================================================
/* - This is the A* algorithm that takes O(nf), f is the faces in the "expansion frontier". */
bool SeLct::_search_channel ( double x1, double y1, double x2, double y2, float radius, const SeFace* iniface )
{
GS_TRACE1 ( "Starting Search Path..." );
if ( !_ptree ) _ptree = new PathTree;
_clear_path(); // clear data from previous query and set _path_result to NoPath
_channel.size(0);
_xi=x1; _yi=y1; _xg=x2; _yg=y2;
if ( !iniface ) return false;
// Even if p1 is on an edge, locate_point will return in s a face that
// can be considered to contain p1 (p1 would be invalid if in a vertex)
SeBase *s;
LocateResult res=locate_point ( iniface, x1, y1, s );
if ( res==NotFound )
{ GS_TRACE1 ( "Could not locate first point!" );
_path_result=NoPath;
return false;
}
_fi = s->fac(); // save initial face
if ( !pt1circfree(this,s,x1,y1,radius) ) { _path_result=NoPath; return false; }
// Check if we are to solve trivial or local paths, testing if both points are in the same triangle:
if ( _man->in_triangle(s->vtx(),s->nxt()->vtx(),s->nxn()->vtx(),x2,y2) )
{ GS_TRACE1 ( "Both points are in the same triangle..." );
if ( radius==0 )
{ GS_TRACE1 ( "Trivial path returned." );
_path_result=TrivialPath; return true; // this is it
}
if ( !pt2circfree(this,s,x2,y2,radius) )
{ GS_TRACE1 ( "Goal point in same triangle invalid. No path returned." );
_path_result=NoPath; return false;
}
_path_result = _analyze_local_path ( s, radius );
if ( _path_result==TrivialPath )
{ GS_TRACE1 ( "Capsule free. Trivial path returned." );
return true; // path exists
}
else if ( _path_result==LocalPath )
{ GS_TRACE1 ( "Deformable capsule is passable. Local path returned." );
return true; // path exists
}
// at this point the result may be a GlobalPath or a NoPath
GS_TRACE1 ( "Deformable capsule is not passable." );
// we then let the normal entrance analysis and search to proceed.
// the entrance that blocked the capsule will also be blocked but
// there may be a global path to get there so we just do not
// mark the initial face as visited, allowing it to be found by the global search.
}
GS_TRACE1 ( "Searching for a global path..." );
GS_TRACE1 ( "Analyzing entrances..." );
_analyze_entrances ( s, _xi, _yi, radius );
GS_TRACE1 ( "Entrance 0: "<<(_ent[0].type==EntBlocked?"blocked":_ent[0].type==EntTrivial?"trivial":"not trivial") );
GS_TRACE1 ( "Entrance 1: "<<(_ent[1].type==EntBlocked?"blocked":_ent[1].type==EntTrivial?"trivial":"not trivial") );
GS_TRACE1 ( "Entrance 2: "<<(_ent[2].type==EntBlocked?"blocked":_ent[2].type==EntTrivial?"trivial":"not trivial") );
GS_TRACE1 ( "Initializing A* search..." );
_mesh->begin_marking ();
_ptree->init ( radius );
if ( _ent[0].type!=EntBlocked ) _ptreeaddent ( _ent[0].s, _ent[0].top, res==EdgeFound? true:false );
if ( _ent[1].type!=EntBlocked ) _ptreeaddent ( _ent[1].s, _ent[1].top, false );
if ( _ent[2].type!=EntBlocked ) _ptreeaddent ( _ent[2].s, _ent[2].top, false );
if (_searchcb) _searchcb(_sudata);
GS_TRACE1 ( "Expanding leafs..." );
int found = ExpansionNotFinished;
while ( found==ExpansionNotFinished )
found = _expand_lowest_cost_leaf();
_mesh->end_marking ();
if ( found==ExpansionBlocked )
{ GS_TRACE1 ( "Points are not connectable!" );
_path_result = NoPath;
return false;
}
_finalsearchnode = found;
int n = found; // the starting leaf
s = _ptree->nodes[n].ex->sym();
do { _channel.push() = _ptree->nodes[n].ex;
n = _ptree->nodes[n].parent;
} while ( n!=-1 );
_channel.revert();
GS_TRACE1 ( "Path crosses "<<_channel.size()<<" edges." );
_path_result = GlobalPath;
return true;
}
void SeLct::get_search_nodes ( GsArray<SeBase*>& e )
{
e.size ( 0 );
for ( int i=0; i<_ptree->nodes.size(); i++ )
{ e.push() = _ptree->nodes[i].en;
e.push() = _ptree->nodes[i].ex;
}
}
int SeLct::get_search_nodes () const
{
return _ptree? _ptree->nodes.size() : 0;
}
void SeLct::get_search_metric ( GsArray<GsPnt2>& pnts )
{
pnts.size ( 0 );
if ( !_ptree ) return;
for ( int i=0; i<_ptree->nodes.size(); i++ )
{
PathNode& n = _ptree->nodes[i];
if ( n.parent<0 )
{ pnts.push().set ( _xi, _yi ); }
else
{ PathNode& np = _ptree->nodes[n.parent];
pnts.push().set ( np.x, np.y );
}
pnts.push().set ( n.x, n.y );
}
}
void SeLct::get_search_front ( GsArray<SeBase*>& e )
{
e.size ( 0 );
for ( int i=0; i<_ptree->leafs.size(); i++ )
{ e.push() = _ptree->nodes[ _ptree->leafs.elem(i) ].ex;
}
}
//============================ End of File =================================
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