I am currently working on a raytracer project and I just found out a issue with the triangle intersections.
Sometimes, and I don't understand when and why, some of the pixels of the triangle don't appear on the screen. Instead I can see the object right behind it. It only occurs on one dimension of the triangle and it depends on the camera and the triangle postions (e.g. picture below).
Triangle with pixels missing
I am using Möller-Trumbore algorithm to compute every intersection. Here's my implementation :
t_solve s;
t_vec v1;
t_vec v2;
t_vec tvec;
t_vec pvec;
v1 = vec_sub(triangle->point2, triangle->point1);
v2 = vec_sub(triangle->point3, triangle->point1);
pvec = vec_cross(dir, v2);
s.delta = vec_dot(v1, pvec);
if (fabs(s.delta) < 0.00001)
return ;
s.c = 1.0 / s.delta;
tvec = vec_sub(ori, triangle->point1);
s.a = vec_dot(tvec, pvec) * s.c;
if (s.a < 0 || s.a > 1)
return ;
tvec = vec_cross(tvec, v1);
s.b = vec_dot(dir, tvec) * s.c;
if (s.b < 0 || s.a + s.b > 1)
return ;
s.t1 = vec_dot(v2, tvec) * s.c;
if (s.t1 < 0)
return ;
if (s.t1 < rt->t)
{
rt->t = s.t1;
rt->last_obj = triangle;
rt->flag = 0;
}
The only clue at the moment is that by using a different method of calculating my ray (called dir in the code), the result is that I have less pixels missing.
Moreover, when I turn the camera and look behind, I see that the bug occurs on the opposite side of the triangle. All of this make me think that the issue is mainly linked with the ray..
Take a look at Watertight Ray/Triangle Intersection. I would much appropriate if you could provide a minimal example where a ray should hit the triangle, but misses it. I had this a long time ago with the Cornel Box - inside the box there were some "black" pixels because on edges none of the triangles has been hit. It's a common problem stemming from floating-point imprecision.
I am trying to understand the way ffmpeg draws motion vectors.
I went through the vf_codecview.c file and saw the function draw_arrow which takes only those vectors where source > 0 implying only those from the future.
Does anyone know why is this? And what's the use of computing past and future, if ffmpeg through this file takes only the future?
Doesn't appear to be the case
source can take on either positive or negative value.
/**
* Where the current macroblock comes from; negative value when it comes
* from the past, positive value when it comes from the future.
* XXX: set exact relative ref frame reference instead of a +/- 1 "direction".
*/
int32_t source;
In the call you linked to, we have
if ((direction == 0 && (s->mv & MV_P_FOR) && frame->pict_type == AV_PICTURE_TYPE_P) ||
(direction == 0 && (s->mv & MV_B_FOR) && frame->pict_type == AV_PICTURE_TYPE_B) ||
(direction == 1 && (s->mv & MV_B_BACK) && frame->pict_type == AV_PICTURE_TYPE_B))
draw_arrow(frame->data[0], mv->dst_x, mv->dst_y, mv->src_x, mv->src_y,
frame->width, frame->height, frame->linesize[0],
100, 0, mv->source > 0);
If the macroblock is predicted from a past frame, the last expression evaluates to and is passed as 0, else 1.
The conditional clearly allows for both past- and future- predicted macroblocks.
P.S. you are looking at the source for ver 2.5, which is very old, at this point. Current version is at https://ffmpeg.org/doxygen/trunk/vf__codecview_8c_source.html#l00256
I'm a bit of an openGL/programming noobie so I'm trying to make an "AI" for the right paddle. I know this isnt the proper way of doing it, what I SHOULD be doing is making it follow the ball. But right now I'm just trying to make it perpetually move up and down. I can't figure out how to do it, trying to use If loops like
if (paddle.pos[1] > 1){
paddle.pos[1] = paddle.pos[1] - delta}
I set delta to something like 0.01, 1 is the top of the screen. Obviously this isnt right because as soon as it goes down below 1 it goes up again, but I'm trying to do something like it.
2nd question - How do you move the ball from 0,0 when it starts? Kind of the same problem, am using if statements with the x values but thats definitely not right.
This is using C by the way.
Try something like this to make pos repeatedly go from 0 to 1 and back to 0:
// Initialize.
float pos = 0.0f;
float delta = 0.01f;
// On every update.
pos += delta;
if (pos > 1.0f) {
pos = 1.0f;
delta = -delta;
} else if (pos < 0.0f) {
pos = 0.0f;
delta = -delta;
}
The key here is that you invert the sign of your increment each time you reach one of the end positions.
I have a DICOM image with a mask on. It looks like a black background with a white circle in the middle (area not covered and zeroed with the mask).
The code for which is:
import numpy as np
import dicom
import pylab
ds = dicom.read_file("C:\Users\uccadmin\Desktop\James_Phantom_CT_Dec_16th\James Phantom CT Dec 16th\Images\SEQ4Recon_3_34\IM-0268-0001.dcm")
lx, ly = ds.pixel_array.shape
X, Y = np.ogrid[0:lx, 0:ly]
mask = (X - lx/2)**2 + (Y - ly/2)**2 > lx*ly/8 # defining mask
ds.pixel_array[mask] = 0
print np.std(ds.pixel_array) # trying to get standard deviation
pylab.imshow(ds.pixel_array, cmap=pylab.cm.bone) # shows image with mask
I want to get the standard deviation of the pixel values INSIDE the white circle ONLY i.e. exclude the black space outside the circle (the mask).
I do not think the value I am getting with the above code is correct, as it is ~500, and the white circle is almost homogenous.
Any ideas how to make sure that I get the standard deviation of the pixel values within the white circle ONLY in a Pythonic way?
I think the reason you are getting a big number is because your standard deviation is including all the zero values.
Is it enough for you to simply ignore all zero values? (This will be okay, providing that no or very few pixels in the circle have value 0.) If so
np.std([x for x in ds.pixel_array if x > 0])
should do the trick. If this isn't good enough, then you can reverse the condition in your mask to be
mask = (X - lx/2)**2 + (Y - ly/2)**2 < lx*ly/8 # defining mask, < instead of >
and do
mp.std(ds.pixel_array[mask])
I am looking for an algorithm to prune short line segments from the output of an edge detector. As can be seen in the image (and link) below, there are several small edges detected that aren't "long" lines. Ideally I'd like just the 4 sides of the quadrangle to show up after processing, but if there are a couple of stray lines, it won't be a big deal... Any suggestions?
Image Link
Before finding the edges pre-process the image with an open or close operation (or both), that is, erode followed by dilate, or dilate followed by erode. this should remove the smaller objects but leave the larger ones roughly the same.
I've looked for online examples, and the best I could find was on page 41 of this PDF.
I doubt that this can be done with a simple local operation. Look at the rectangle you want to keep - there are several gaps, hence performing a local operation to remove short line segments would probably heavily reduce the quality of the desired output.
In consequence I would try to detect the rectangle as important content by closing the gaps, fitting a polygon, or something like that, and then in a second step discard the remaining unimportant content. May be the Hough transform could help.
UPDATE
I just used this sample application using a Kernel Hough Transform with your sample image and got four nice lines fitting your rectangle.
In case somebody steps on this thread, OpenCV 2.x brings an example named squares.cpp that basically nails this task.
I made a slight modification to the application to improve the detection of the quadrangle
Code:
#include "highgui.h"
#include "cv.h"
#include <iostream>
#include <math.h>
#include <string.h>
using namespace cv;
using namespace std;
void help()
{
cout <<
"\nA program using pyramid scaling, Canny, contours, contour simpification and\n"
"memory storage (it's got it all folks) to find\n"
"squares in a list of images pic1-6.png\n"
"Returns sequence of squares detected on the image.\n"
"the sequence is stored in the specified memory storage\n"
"Call:\n"
"./squares\n"
"Using OpenCV version %s\n" << CV_VERSION << "\n" << endl;
}
int thresh = 70, N = 2;
const char* wndname = "Square Detection Demonized";
// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
double angle( Point pt1, Point pt2, Point pt0 )
{
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
void findSquares( const Mat& image, vector<vector<Point> >& squares )
{
squares.clear();
Mat pyr, timg, gray0(image.size(), CV_8U), gray;
// karlphillip: dilate the image so this technique can detect the white square,
Mat out(image);
dilate(out, out, Mat(), Point(-1,-1));
// then blur it so that the ocean/sea become one big segment to avoid detecting them as 2 big squares.
medianBlur(out, out, 3);
// down-scale and upscale the image to filter out the noise
pyrDown(out, pyr, Size(out.cols/2, out.rows/2));
pyrUp(pyr, timg, out.size());
vector<vector<Point> > contours;
// find squares only in the first color plane
for( int c = 0; c < 1; c++ ) // was: c < 3
{
int ch[] = {c, 0};
mixChannels(&timg, 1, &gray0, 1, ch, 1);
// try several threshold levels
for( int l = 0; l < N; l++ )
{
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if( l == 0 )
{
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
Canny(gray0, gray, 0, thresh, 5);
// dilate canny output to remove potential
// holes between edge segments
dilate(gray, gray, Mat(), Point(-1,-1));
}
else
{
// apply threshold if l!=0:
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
gray = gray0 >= (l+1)*255/N;
}
// find contours and store them all as a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
vector<Point> approx;
// test each contour
for( size_t i = 0; i < contours.size(); i++ )
{
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
if( approx.size() == 4 &&
fabs(contourArea(Mat(approx))) > 1000 &&
isContourConvex(Mat(approx)) )
{
double maxCosine = 0;
for( int j = 2; j < 5; j++ )
{
// find the maximum cosine of the angle between joint edges
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
maxCosine = MAX(maxCosine, cosine);
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if( maxCosine < 0.3 )
squares.push_back(approx);
}
}
}
}
}
// the function draws all the squares in the image
void drawSquares( Mat& image, const vector<vector<Point> >& squares )
{
for( size_t i = 1; i < squares.size(); i++ )
{
const Point* p = &squares[i][0];
int n = (int)squares[i].size();
polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, CV_AA);
}
imshow(wndname, image);
}
int main(int argc, char** argv)
{
if (argc < 2)
{
cout << "Usage: ./program <file>" << endl;
return -1;
}
static const char* names[] = { argv[1], 0 };
help();
namedWindow( wndname, 1 );
vector<vector<Point> > squares;
for( int i = 0; names[i] != 0; i++ )
{
Mat image = imread(names[i], 1);
if( image.empty() )
{
cout << "Couldn't load " << names[i] << endl;
continue;
}
findSquares(image, squares);
drawSquares(image, squares);
imwrite("out.jpg", image);
int c = waitKey();
if( (char)c == 27 )
break;
}
return 0;
}
The Hough Transform can be a very expensive operation.
An alternative that may work well in your case is the following:
run 2 mathematical morphology operations called an image close (http://homepages.inf.ed.ac.uk/rbf/HIPR2/close.htm) with a horizontal and vertical line (of a given length determined from testing) structuring element respectively. The point of this is to close all gaps in the large rectangle.
run connected component analysis. If you have done the morphology effectively, the large rectangle will come out as one connected component. It then only remains iterating through all the connected components and picking out the most likely candidate that should be the large rectangle.
Perhaps finding the connected components, then removing components with less than X pixels (empirically determined), followed by dilation along horizontal/vertical lines to reconnect the gaps within the rectangle
It's possible to follow two main techniques:
Vector based operation: map your pixel islands into clusters (blob, voronoi zones, whatever). Then apply some heuristics to rectify the segments, like Teh-Chin chain approximation algorithm, and make your pruning upon vectorial elements (start, endpoint, length, orientation and so on).
Set based operation: cluster your data (as above). For every cluster, compute principal components and detect lines from circles or any other shape by looking for clusters showing only 1 significative eigenvalue (or 2 if you look for "fat" segments, that could resemble to ellipses). Check eigenvectors associated with eigenvalues to have information about orientation of the blobs, and make your choice.
Both ways could be easily explored with OpenCV (the former, indeed, falls under "Contour analysis" category of algos).
Here is a simple morphological filtering solution following the lines of #Tom10:
Solution in matlab:
se1 = strel('line',5,180); % linear horizontal structuring element
se2 = strel('line',5,90); % linear vertical structuring element
I = rgb2gray(imread('test.jpg'))>80; % threshold (since i had a grayscale version of the image)
Idil = imdilate(imdilate(I,se1),se2); % dilate contours so that they connect
Idil_area = bwareaopen(Idil,1200); % area filter them to remove the small components
The idea is to basically connect the horizontal contours to make a large component and filter by an area opening filter later on to obtain the rectangle.
Results: