I'm playing around with XNA DirectShow to stream a video from a file rather than loading it into my project (I'm fully aware of the XNA MediaPlayer class by the way). It plays the sample video it came with no problem. When I try to make my own .wmv from a series of PNG files I have using ffmpeg the video plays but is all blue (should be mostly yellow). Pixel format wrong? Wrong codec? I'm certainly no expert in these waters..
The sample video is a VC-1 WMV3 apparantly, and I don't think I can replicate that? What encoding/codec/fileformat should I be using?
Also! If transparent video background is possible, that would be amazing. Is it?
Ok I've solved it - I simply switched the order pixels are assigned to when DirectShow creates its output texture. In the VideoPlayer class I changed UpdateBuffer to:
private void UpdateBuffer()
{
int waitTime = avgTimePerFrame != 0 ? (int)((float)avgTimePerFrame / 10000) : 20;
int samplePosRGBA = 0;
int samplePosRGB24 = 0;
while (true)
{
for (int y = 0, y2 = videoHeight - 1; y < videoHeight; y++, y2--)
{
for (int x = 0; x < videoWidth; x++)
{
samplePosRGBA = (((y2 * videoWidth) + x) * 4);
samplePosRGB24 = ((y * videoWidth) + x) * 3;
//make transparent if pixel matches a certain colour
if (WhiteTransparent && bgrData[samplePosRGB24 + 2] > 200 && bgrData[samplePosRGB24 + 1] > 200 && bgrData[samplePosRGB24 + 0] > 200)
{
//transparent pixel
videoFrameBytes[samplePosRGBA + 0] = 0;
videoFrameBytes[samplePosRGBA + 1] = 0;
videoFrameBytes[samplePosRGBA + 2] = 0;
videoFrameBytes[samplePosRGBA + 3] = 0;
}
else
{
//modified pixel format order - switch the 2,1,0 on the right for other formats..
videoFrameBytes[samplePosRGBA + 0] = bgrData[samplePosRGB24 + 2];
videoFrameBytes[samplePosRGBA + 1] = bgrData[samplePosRGB24 + 1];
videoFrameBytes[samplePosRGBA + 2] = bgrData[samplePosRGB24 + 0];
videoFrameBytes[samplePosRGBA + 3] = alphaTransparency;
}
}
}
frameAvailable = false;
while (!frameAvailable)
{ Thread.Sleep(waitTime); }
}
}
which also displays any white areas as transparent in the final image if a bool I added to the class - WhiteTransparent is true. Crude I know, but it's doing the trick for me. Just use the lines in the else statement if not desired.
Related
I have two images with similar sizes that show similar scenes. How can we show two images in two frames and when panning or zooming in the left image, it pans and zooms in the right one? I don't want to concatenate the images though.
Is there a solution to do this? Both python or c++ OpenCV are fine.
About zoom in/out:
The basic idea is deciding the scale changed every time on mouse wheel. After you get the current scale (v.s. origin image) and correct region of image you want to show on screen, you can get the position and length of rectangle on scaled image. So you can draw this rectangle on scaled image.
In my github,checking OnMouseWheel () and RefreshSrcView () in Fastest_Image_Pattern_Matching/ELCVMatchTool/ELCVMatchToolDlg.cpp may give what you want.
About showing two images simutaneouly with same region:
use two picture boxes with MFC framework or other UI builder.
or use two cv::namedWindow () without framework
Effect:
Part of the code:
BOOL CELCVMatchToolDlg::OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)
{
POINT pointCursor;
GetCursorPos (&pointCursor);
ScreenToClient (&pointCursor);
// TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
if (zDelta > 0)
{
if (m_iScaleTimes == MAX_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes++;
}
if (zDelta < 0)
{
if (m_iScaleTimes == MIN_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes--;
}
CRect rect;
//GetWindowRect (rect);
GetDlgItem (IDC_STATIC_SRC_VIEW)->GetWindowRect (rect);//重要
if (m_iScaleTimes == 0)
g_dCompensationX = g_dCompensationY = 0;
int iMouseOffsetX = pt.x - (rect.left + 1);
int iMouseOffsetY = pt.y - (rect.top + 1);
double dPixelX = (m_hScrollBar.GetScrollPos () + iMouseOffsetX + g_dCompensationX) / m_dNewScale;
double dPixelY = (m_vScrollBar.GetScrollPos () + iMouseOffsetY + g_dCompensationY) / m_dNewScale;
m_dNewScale = m_dSrcScale * pow (SCALE_RATIO, m_iScaleTimes);
if (m_iScaleTimes != 0)
{
int iWidth = m_matSrc.cols;
int iHeight = m_matSrc.rows;
m_hScrollBar.SetScrollRange (0, int (m_dNewScale * iWidth - m_dSrcScale * iWidth) - 1 + BAR_SIZE);
m_vScrollBar.SetScrollRange (0, int (m_dNewScale * iHeight - m_dSrcScale * iHeight) - 1 + BAR_SIZE);
int iBarPosX = int (dPixelX * m_dNewScale - iMouseOffsetX + 0.5);
m_hScrollBar.SetScrollPos (iBarPosX);
m_hScrollBar.ShowWindow (SW_SHOW);
g_dCompensationX = -iBarPosX + (dPixelX * m_dNewScale - iMouseOffsetX);
int iBarPosY = int (dPixelY * m_dNewScale - iMouseOffsetY + 0.5);
m_vScrollBar.SetScrollPos (iBarPosY);
m_vScrollBar.ShowWindow (SW_SHOW);
g_dCompensationY = -iBarPosY + (dPixelY * m_dNewScale - iMouseOffsetY);
//滑塊大小
SCROLLINFO infoH;
infoH.cbSize = sizeof (SCROLLINFO);
infoH.fMask = SIF_PAGE;
infoH.nPage = BAR_SIZE;
m_hScrollBar.SetScrollInfo (&infoH);
SCROLLINFO infoV;
infoV.cbSize = sizeof (SCROLLINFO);
infoV.fMask = SIF_PAGE;
infoV.nPage = BAR_SIZE;
m_vScrollBar.SetScrollInfo (&infoV);
//滑塊大小
}
else
{
m_hScrollBar.SetScrollPos (0);
m_hScrollBar.ShowWindow (SW_HIDE);
m_vScrollBar.SetScrollPos (0);
m_vScrollBar.ShowWindow (SW_HIDE);
}
RefreshSrcView ();
return CDialogEx::OnMouseWheel (nFlags, zDelta, pt);
}
I'm trying to load in heightmap data but I'm struggling to figure out how to work out the normals. Have looked online but can't seem to find anything useful.
I store the vertices using
m_HeightMapVtxCount = (m_HeightMapLength - 1) * m_HeightMapWidth * 2;
m_pVertices = new XMFLOAT3[m_HeightMapVtxCount];
Then the vertices are loaded in using
for (int l = 0; l < m_HeightMapLength - 1; ++l)
{
if(l % 2 == 0) //for every second row - start at the bottom left corner, continue to the right, one row up and continue to the left
{
for(int w = 0; w < m_HeightMapWidth; ++w)
{
m_pVertices[i++] = XMFLOAT3(m_pHeightMap[w + l * m_HeightMapWidth]); //bottom vertex
m_pVertices[i++] = XMFLOAT3(m_pHeightMap[w + (l + 1) * m_HeightMapWidth]); //top vertex
}
}
else //for the row above, add the vertices from right to left
{
for(int w = m_HeightMapWidth - 1; w >= 0; --w)
{
m_pVertices[i++] = XMFLOAT3(m_pHeightMap[w + l * m_HeightMapWidth]); //bottom vertex
m_pVertices[i++] = XMFLOAT3(m_pHeightMap[w + (l + 1) * m_HeightMapWidth]); //top vertex
}
}
}
I was able to calculate the normals using triangle lists, that was quite simple, but unsure of how to do it using strips
I have a huge image ( about 63000 x 63000 pixels = 3969 Megapixels )
what i have done so far is i decided to make "tiles" of (1024 x 1024) and do my calculations based on these tiles, resulting in an 62 x 62 image tile grid!
(this works out very well and has the advantage of making the image viewable with zoom-in and zoom out, only viewn tiles are downsized for example)
But what i need now are the contours from the huge image!
i use the OpenCV function "findContours" to detect contours on each
one of the tiles.
i have added some overlap in the tiles so i get
overlapping contours ( 1 pixel overlap )
i used the offset parameter
of "findContours" to shift the contours to the right position
into the "virtual total image"
Here are some screenshot's i made from a demo application
What I want is this:
Now my questions:
is it possible to stitch the contours, my worst case is a contour which covers the total image... is there some library that can do this?
is there a library which works on a compressed version of the total image ( like rle for example )
is there a way to make opencv findcontours work on 1 bit binary images ?
Here's the code used by findcontours:
// Surf2DTiledData ...a gobject based class used for 2d tile management and viewing..
Surf2DTiledData* td = (Surf2DTiledData*)in_td;
int nr_hor_tiles = surf2_d_tiled_data_get_nr_hor_tiles(td);
int nr_ver_tiles = surf2_d_tiled_data_get_nr_ver_tiles(td);
int tile_size_x = surf2_d_tiled_data_get_tile_width(td);
int tile_size_y = surf2_d_tiled_data_get_tile_height(td);
contouring_data_obj = surf2_d_tiled_data_get_ContouringData(td);
p_contours = contouring_data_obj->p_contours;
p_border_contours = contouring_data_obj->p_border_contours;
g_return_if_fail(p_border_contours != NULL);
g_return_if_fail(p_contours != NULL);
for (y = 0; y < nr_ver_tiles; y++){
int x;
for (x = 0; x < nr_hor_tiles; x++){
int idx = x + y*nr_hor_tiles;
CvMemStorage *mem = contouring_data_obj->contour_storage[idx];
CvMat _src;
CvSeq *contours = NULL;
uchar* dataBuffer = (uchar*)p_data[x][y];
// the idea is to have some extra space available for the overlap
// detection of contours!
// the extra space is needed for the algorithm to check for
// overlaps of contours later on!
#define VIRT_BORDER_EXTEND 2
int virtual_x = x * tile_size_x - VIRT_BORDER_EXTEND;
int virtual_y = y * tile_size_y - VIRT_BORDER_EXTEND;
int virtual_width = tile_size_x + VIRT_BORDER_EXTEND * 2;
int virtual_height = tile_size_y + VIRT_BORDER_EXTEND * 2;
int x_off = -VIRT_BORDER_EXTEND;
int y_off = -VIRT_BORDER_EXTEND;
if (virtual_x < 0) {
virtual_width += virtual_x;
virtual_x = 0;
x_off = 0;
}
if (virtual_y < 0) {
virtual_height += virtual_y;
virtual_y = 0;
y_off = 0;
}
if ((virtual_x + virtual_width) > (nr_hor_tiles*tile_size_x)) {
virtual_width = nr_hor_tiles*tile_size_x - virtual_x;
}
if ((virtual_y + virtual_height) > (nr_ver_tiles*tile_size_y)) {
virtual_height = nr_ver_tiles*tile_size_y - virtual_y;
}
CvMat* _roi_mat = get_roi_mat(td,
virtual_x, virtual_y,
virtual_width, virtual_height);
// Use either this:
//mem = cvCreateMemStorage(0);
if (_roi_mat){
// CV_LINK_RUNS => different algorithm!!!!
int tile_off_x = tile_size_x * x;
int tile_off_y = tile_size_y * y;
CvPoint contour_shift = cvPoint(x_off + tile_off_x, y_off + tile_off_y);
int n = cvFindContours(_roi_mat, mem, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, contour_shift);
cvReleaseMat(&_roi_mat);
p_contours[x][y] = contours;
}
//cvReleaseMemStorage(&mem);
}
}
later i used opengl to make textures out of the tiles and for every tile there is a quad !
the opencv contours are not drawn as this could be too slow for now, but i draw their bounding boxes... which are drawn in opengl too..
I am wondering how to actually sample the data I am passing to the shader file. I am using two methods, is it the same for both? Are there any resources online for me to actually read up on this sort of thing?
Compiling at 5.0 but the version number does not matter so much.
I have two methods to pass the data.
The first;
for( UINT row = 0; row < textureDesc.Height; row++ )
{
UINT rowStart = row * mappedResource.RowPitch;
for( UINT col = 0; col < textureDesc.Width; col++ )
{
//width * number of channels (r,g,b,a)
UINT colStart = col * 4;
pTexels[rowStart + colStart + 0] = 10.0f; // Red
pTexels[rowStart + colStart + 1] = 10.0f; // Green
pTexels[rowStart + colStart + 2] = 255.0f; // Blue
pTexels[rowStart + colStart + 3] = 255.0f; // Alpha
}
}
The second;
float elements[416][416];
int elementsCount = 416*416;
for( int i = 0; i < 416; i++ )
{
for( int k = 0; k < 416; k++ )
{
elements[i][k] = 0;
}
}
memcpy(mappedResource.pData, elements, sizeof(float) * elementsCount);
Seems that I missed an important part of all of this.
When creating a texture, in the texture description, the Format is the type that will be returned when the object is sampled. Many thanks to Drop for the help.
I am trying to implement Hough Transform for line detection in an already pre-processed image.
So my input image is a black-white edge image, 0 - background and 255 - foreground. I do not wish to use the inbuilt HoughLines library by OpenCV.
I am actually stuck with creating the accumulator and increasing its values properly. I cant figure out where i went wrong, so here is my code block :
int diagonal = sqrt(height * height + width * width);
IplImage *acc = cvCreateImage (cvSize(180, 2 * diagonal),IPL_DEPTH_8U, 1);
unsigned char* accData = (unsigned char *)acc->imageData;
for (int i=0; i<height; i++)
{
for (int j=0; j<step; j++)
{
if (data[i*step + j] > 200)
{
for (int theta=0; theta<180; theta++)
{
int p = j * cos(theta) + i * sin(theta);
if (p > 0)
accData[theta*180 + p] += 1;
}
}
}
}
The output image that i get in acc is not what it should look like. I am not getting any sinusoids, instead only white patches here and there. Can anyone provide any feedback about where i went wrong ?
What I see there is that you don t use sinus with radians values but with degree values you could change it as follows:
int p = j * cos((double)theta*PI/180) + i * sin((double)theta*PI/180);