My question is related to the use of matchTemplate in OpenCV. I'm able to use the function to find a template within the whole image. It is possible to limit the "searching area" to a restricted region within the image, i.e. using the roi? I tried to set the roi before calling matchTemplate but that didn't have any effect.
So, do you know any way to limit the search of the template to a subregion of the image? That because I know that my target can be found only in this limited region.
Here is some line of code taken directly from the OpenCV samples:
void MatchingMethod( int, void* )
{
// Source image to display
Mat img_display;
img.copyTo( img_display );
// Create the result matrix
int result_cols = img.cols - templ.cols + 1;
int result_rows = img.rows - templ.rows + 1;
result.create( result_cols, result_rows, CV_32FC1 );
// Do the Matching and Normalize
img.adjustROI(100, 100, 500, 500);
matchTemplate( img, templ, result, match_method );
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
// Localizing the best match with minMaxLoc
double minVal; double maxVal; Point minLoc; Point maxLoc;
Point matchLoc;
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
{ matchLoc = minLoc; }
else
{ matchLoc = maxLoc; }
// Show me what you got
rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
imshow( image_window, img_display );
imshow( result_window, result );
}
sure !
Rect roi( x,y,w,h );
matchTemplate( img( roi ), templ, result, method );
Related
i have about 10 objects that filters can be applied to, and a filter engine that goes through them one by one and applies filters to each.
import { fabric } from 'fabric'
const filters = {
brightness: new fabric.Image.filters.Brightness(),
premade: new fabric.Image.filters.ColorMatrix(),
}
const addFilter = (canvas, index, value = null) => {
let pickedFilter
let objects = canvas.getObjects()
switch (index) {
case 1:
pickedFilter = sepia
break;
case 8:
pickedFilter = brightness
break;
default:
break;
}
objects.forEach((o) => {
if (o.filters) {
if (!o.filters[0]) {
o.filters.push(filters.brightness)
o.filters.push(filters.premade)
}
pickedFilter(o, value)
}
});
canvas.renderAll();
}
export default addFilter
function sepia(o){
let value = [
0.67, 0, 0, 0, 0,
0, 0.54, 0, 0, 0,
0, 0, 0.4, 0, 0,
0, 0, 0, 1, 0
]
delete filters.contrast.contrast
delete filters.premade.matrix
filters.premade.matrix = value
o.applyFilters()
}
function brightness(o, value) {
value = (value / 100) / 2
filters.brightness.brightness = value
o.applyFilters()
}
initally when objects don't have filter at filters[0], i go ahead and push the filters.
later on when the user moves the slider like in this gif, i go through each object and if it can have filters i go ahead and change the value of filter and then apply the filters. as you can see it's a bit laggy and i think the biggest problem is that there are multiple objects that filters are applied to.
in this gif, i get rid of all objects but one and i can feel that the performance is better, but the problem is that i need to apply the filters to all of the objects.
i tried running the code inside filter functions only once (for example i put the value asignment, deletion of previous value and value asignment inside sepia funtion, outside the loop), but it didn't change anything.
how can i improve the performance and make it less laggy?
simple by using rapheal i successfully make animation along path , but i can't reverse the animation direction ,,, just how to make it animate to the other direction when clicking the same path .
var paper = Raphael(0,0,1024,768);
var pathOne = paper.path(['M', 15,15 , 100,75]).attr({'stroke-width':18}).data("id",1);
//and this is just the circle
var circle = paper.circle(0, 0, 13).attr({
fill: '#09c', cursor: 'pointer'
});
//make the path as custom attribute so it can ba accessed
function pathPicker(thatPath){
paper.customAttributes.pathFactor = function(distance) {
var point = thatPath.getPointAtLength(distance * thatPath.getTotalLength());
var dx = point.x,
dy = point.y;
return {
transform: ['t', dx, dy]
};
}
}
//initialize for first move
pathPicker(pathOne);
circle.attr({pathFactor: 0}); // Reset
//Asign first path and first move
function firstMove(){
circle.animate({pathFactor: 1}, 1000});
}
pathOne.click(function(){
firstMove();
});
I couldn't get the original to run, so here is something using the main bits that should suit...
There's not a lot to it, get the length of the path, iterate over the length, draw object at the path. It uses the Raphael customAttributes to be able to animate it. I've added a custom toggle to make it easy to switch between them.
These are the key changes..
var len = pathOne.getTotalLength();
paper.customAttributes.along = function (v) {
var point = pathOne.getPointAtLength(v * len);
return {
transform: "t" + [point.x, point.y] + "r" + point.alpha
};
};
circle.attr({ along: 0 });
function animateThere( val ) {
val = +!val; // toggle
pathOne.click( function() { animateThere( val ) } );
circle.animate({ along: val }, 2000 );
};
pathOne.click( function() { animateThere(0) } );
jsfiddle
For completeness, you may want to do some extra checks like only allow the click if the animation has finished or something, as there may be a problem if you quickly click a lot and it buffering up animations.
I am using visual c++ gdal to read .gis file from my desktop and then output the image of that file (png/jpeg). The code accepts the "input.gis" file and then creates "output.png".
Here is my working code :
GDALDriver *poDriver;
GDALDataset *poDataset;
char **papszMetadata;
double adfGeoTransform[6];
int nBlockXSize, nBlockYSize;
int bGotMin, bGotMax;
double adfMinMax[2];
GDALAllRegister();
poDataset = (GDALDataset *) GDALOpen("C:\\input.gis", GA_ReadOnly );
if( poDataset == NULL )
{
MessageBox::Show("cannot open");
}
else
{
poDataset->GetGeoTransform( adfGeoTransform );
GDALRasterBand *poBand;
poBand = poDataset->GetRasterBand( 1 );
float *pafScanline;
int nXSize = poBand->GetXSize();
poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
adfMinMax[0] = poBand->GetMinimum( &bGotMin );
adfMinMax[1] = poBand->GetMaximum( &bGotMax );
if( ! (bGotMin && bGotMax) )
GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);
poDriver = GetGDALDriverManager()->GetDriverByName("PNG");
if( poDriver == NULL )
printf("Cannot create image");
else
{
papszMetadata = poDriver->GetMetadata();
if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATECOPY, FALSE ) )
{
printf( "Driver %s supports CreateCopy() method.\n", "png" );
}
}
GDALDataset *poDstDS;
poDstDS = poDriver->CreateCopy( "C:\\output.png", poDataset, FALSE, NULL, NULL, NULL );
if( poDstDS != NULL )
GDALClose( (GDALDatasetH) poDstDS );
GDALClose( (GDALDatasetH) poDataset );
}
My problem is when I use createcopy() function from gdal the size of image output is always 99 X 99 (which i guess is the default size). How can I increase the size of image to be outputted for example (512 x 512 )?
The dimensions of your output dataset output.png are 99 x 99 because those are also the dimensions of your input dataset input.gis. To create a new dataset with different dimensions you need to use the Create method as described in the GDAL tutorial.
The PNG driver unfortunately does not support this method which leaves you with two options:
Choose a different output format which supports the Create method.
Use the Create method to create a dataset in your memory and then use CreateCopy on it - as suggestested in this GIS.SE post
another ThreeJS question:
How can I make a hovered (intersected) object scale smooth to a defined size? My current code is
INTERSECTED.scale.x *= 1.5;
INTERSECTED.scale.y *= 1.5;
but this only works like on/off.
Edit: My Solution (with tweenJS)
While mouseOver I scale up the element to 200% :
function scaleUp(){
new TWEEN.Tween( INTERSECTED.scale ).to( {
x: 2,
y: 2
}, 350 ).easing( TWEEN.Easing.Bounce.EaseOut).start();
}
While mouseOut I scale down the element to 100% :
function scaleDown(){
new TWEEN.Tween( INTERSECTED.scale ).to( {
x: 1,
y: 1
}, 350 ).easing( TWEEN.Easing.Bounce.EaseOut).start();
}
Finally I call the functions in the mouse function.
if (intersects[0].object != INTERSECTED)
scaleUp();
else
scaleDown();
That's all. Very useful for UIs I think.
Using the tween library (found in three.js/examples/js/libs/tween.min.js) you can animate the scale like so:
function setupObjectScaleAnimation( object, source, target, duration, delay, easing )
{
var l_delay = ( delay !== undefined ) ? delay : 0;
var l_easing = ( easing !== undefined ) ? easing : TWEEN.Easing.Linear.None;
new TWEEN.Tween( source )
.to( target, duration )
.delay( l_delay )
.easing( l_easing )
.onUpdate( function() { object.scale.copy( source ); } )
.start();
}
and then call it like so:
setupObjectScaleAnimation( INTERSECTED,
{ x: 1, y: 1, z: 1 }, { x: 2, y: 2, z: 2 },
2000, 500, TWEEN.Easing.Linear.None );
Or if you want to use the render loop:
clock = new THREE.Clock();
time = clock.getElapsedTime();
INSPECTED.scale.x = time / 1000;
INSPECTED.scale.y = time / 1000;
You can change the divisor based on how fast or slow you want the animation to happen.
One often wants to make a set of objects in Raphael draggable, but using .transform() to do so can be maddening. Say you start like this:
var paper = Raphael(0, 0, 500, 500);
var set = paper.set();
set.push(paper.circle(100,100,35), paper.circle(150,150,15));
set.attr("fill", "orange");
set.data("myset", set);
set.drag(
function(dx, dy, x, y, e) {
this.data('myset').transform("T" + dx + "," + dy);
},
function(x, y, e) {},
function(e) {}
);
If you try this out, you see it works once. But if you drag, stop, then drag again, it resets the position to 0,0 relative to the original position, as you'd expect from .transform(). No good.
A variant of this question has been touched on here, and the respondent suggested prepending transforms with "...". That's all fine and good, but for two things:
you still have to track previous position, since you don't want to
translate by (dx,dy) on every call of dragmove, which will send
the objects flying off the screen.
I worry about creating a monster
transform if an object is dragged many times. (Though maybe I
shouldn't.)
My tentative solution is to track the offset from the original positioning in another key/value pair, like so:
var paper = Raphael(0, 0, 500, 500);
var set = paper.set();
set.push(
paper.circle(100,100,35),
paper.circle(150,150,15)
);
set.attr("fill", "orange");
set.data("myset", set);
set.data("position", [0,0]);
var current_position = [0,0];
set.drag(
function(dx, dy, x, y, e) {
this.data('myset').transform("T" + (this.data("position")[0] + dx) + "," + (this.data("position")[1] + dy));
current_position = [dx,dy];
},
function(x, y, e) {
},
function(e) {
this.data('myset').data("position", [
this.data("position")[0] += current_position[0],
this.data("position")[1] += current_position[1]
]);
}
);
You can see it in action here.
It works, but it feels incredibly sloppy. I must be missing something obvious, right?
My answer is similar to your last variant:
var onmove = function (dx,dy){
this.transform(this.default_transform+'T'+dx+','+dy);
},
onstart = function (){
this.default_transform = this.transform();
},
onend = function(){
this.default_transform = this.transform();
};
set.drag(onmove, onstart, onend);
Don't worry it won't create a long long line of transformations because Raphael converts everything to one whole matrix transformation so it doesn't build up each time you move an object.