longest line in image hough - performance

I'm going to find lines in an image, so I use hough transform to do it.
But now I'm trying to find the longest line in the image(there must exist a longest line in my image), is there any method to do it without sacrifice the computation speed?
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap("D:\\DataBox\\v0.avi");
if (!cap.isOpened())
cout << "fail to open!" << endl; //return -1;
else
cout << "Video Load Succeed" << endl;
while (true)
{
cout << "----------------------------------------------------" << endl;
Mat src;
cap >> src;
pyrDown(src, src, Size(src.cols / 2, src.rows / 2));
pyrDown(src, src, Size(src.cols / 2, src.rows / 2));
cvtColor(src, src, CV_BGR2GRAY);
Mat tsrc;
threshold(src, tsrc, 90, 255, THRESH_BINARY_INV);
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
Mat sobel;
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
Sobel(tsrc, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
Sobel(tsrc, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);
convertScaleAbs(grad_y, abs_grad_y);
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, sobel);
vector<Vec2f> lines;
int threshold = 250;
HoughLines(sobel , lines, 1, CV_PI / 180, threshold, 0, 0);
Mat cdst;
cvtColor(sobel, cdst, CV_GRAY2BGR);
for (size_t i = 0; i < lines.size(); i++)
{
float rho = lines[i][0], theta = lines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000 * (-b));
pt1.y = cvRound(y0 + 1000 * (a));
pt2.x = cvRound(x0 - 1000 * (-b));
pt2.y = cvRound(y0 - 1000 * (a));
line(cdst, pt1, pt2, Scalar(0, 0, 255), 3, CV_AA);
}
imshow("Video", cdst);
waitKey(30);
}
}

Related

Optimizing global memory load in CUDA

My task :
I have two matrices : A - (18 x 4194304) ; B - (18 x 1024).
I have to take each 18-length vector from A and compute distance with each 18-length vector from B and find minimum distance and index.
My code :
__device__
void GetMin(float &dist, int &idx)
{
float dist2;
int idx2;
dist2 = __shfl_down_sync(0xFFFFFFFF, dist, 16, 32);
idx2 = __shfl_down_sync(0xFFFFFFFF, idx, 16);
if (dist > dist2)
{
dist = dist2;
idx = idx2;
}
dist2 = __shfl_down_sync(0xFFFFFFFF, dist, 8, 32);
idx2 = __shfl_down_sync(0xFFFFFFFF, idx, 8);
if (dist > dist2)
{
dist = dist2;
idx = idx2;
}
dist2 = __shfl_down_sync(0xFFFFFFFF, dist, 4, 32);
idx2 = __shfl_down_sync(0xFFFFFFFF, idx, 4);
if (dist > dist2)
{
dist = dist2;
idx = idx2;
}
dist2 = __shfl_down_sync(0xFFFFFFFF, dist, 2, 32);
idx2 = __shfl_down_sync(0xFFFFFFFF, idx, 2);
if (dist > dist2)
{
dist = dist2;
idx = idx2;
}
dist2 = __shfl_down_sync(0xFFFFFFFF, dist, 1, 32);
idx2 = __shfl_down_sync(0xFFFFFFFF, idx, 1);
if (dist > dist2)
{
dist = dist2;
idx = idx2;
}
}
__global__
void CalcMinDist_kernel(const float *A, const float *B, float *output, const int nNumPixels, int nNumImages)
{
int tx = threadIdx.x + blockIdx.x * blockDim.x;
int ty = threadIdx.y;
int lane_id = tx % 32;
float dist = 0;
int idx = 0;
float fMin = 99999999;
int nMinIdx = -1;
for(int i = lane_id; i < 1024; i += 32)
{
dist = 0;
for(int j = 0; j < nNumImages; ++j)
{
int img_idx = blockIdx.x * ty + j * nNumPixels;
dist += (A[img_idx] - B[i * nNumImages + j]) *
(A[img_idx] - B[i * nNumImages + j]);
}
idx = i;
GetMin(dist, idx);
if(threadIdx.x == 0)
{
if(fMin > dist)
{
fMin = dist;
nMinIdx = idx;
}
}
}
if(threadIdx.x == 0)
{
output[blockIdx.x * ty] = nMinIdx;
}
}
Looking at the profiler, I'm memory bound, and do have ~90% occupancy. Is there any way to speed up this operation?
Let me know if I need to provide any other information.
Actually, I would look at the algorithm first. This is a geometric problem - treat it as such.
You should represent the B data using a different data structure, e.g. by clustering or building a partition structure (e.g. k-d tree). That will let you avoid actually computing the distance from most B elements. (You could also consider a project onto fewer dimensions, but the benefit of this may be more elusive.)
With respect to the access pattern - you would probably benefit from having consecutive threads working on consecutive elements of the 18-element-long vectors, rather than having threads work on complete 18-element-long vectors individually. That would better fit the memory layout - right now, a warp read is of many elements which are at distance 18 from each other. If I understand the code correctly anyway.
(I also think the GetMin() could avoid some of the index swaps, but that's not significant since you only perform very few of those.)

Creating 24-bit BITMAP in Winapi

I'm using the following code in order to convert my ImageMagick image to 32-bit HBITMAP:
BITMAP bitmap;
std::memset(&bitmap, 0, sizeof(bitmap));
bitmap.bmType = 0;
bitmap.bmWidth = image->image()->columns;
bitmap.bmHeight = image->image()->rows;
bitmap.bmWidthBytes = 4 * bitmap.bmWidth;
bitmap.bmPlanes = 1;
bitmap.bmBitsPixel = 32;
bitmap.bmBits = NULL;
const size_t size = bitmap.bmWidthBytes * bitmap.bmHeight;
auto buffer = (HANDLE)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
RGBQUAD *bitmap_bits = (RGBQUAD *) GlobalLock((HGLOBAL) buffer);
register RGBQUAD *q = bitmap_bits;
for (size_t y = 0; y < image->image()->rows; y++)
{
register auto p = GetVirtualPixels(image->image(), 0, y, image->image()->columns, 1, exception);
if (!p) break;
for (size_t x = 0; x < image->image()->columns; x++)
{
q->rgbRed = ScaleQuantumToChar(GetPixelRed(image->image(), p));
q->rgbGreen = ScaleQuantumToChar(GetPixelGreen(image->image(), p));
q->rgbBlue = ScaleQuantumToChar(GetPixelBlue(image->image(), p));
q->rgbReserved = 0;
p += GetPixelChannels(image->image());
q++;
}
}
bitmap.bmBits = bitmap_bits;
HBITMAP hbmp = CreateBitmapIndirect(&bitmap);
It works well, but I'd like to save some memory by using images with lower depth. Unfortunately I'm not even able to make it work with 24-bit images. I modified my code to look like this:
BITMAP bitmap;
std::memset(&bitmap, 0, sizeof(bitmap));
bitmap.bmType = 0;
bitmap.bmWidth = image->image()->columns;
bitmap.bmHeight = image->image()->rows;
bitmap.bmWidthBytes = ((bitmap.bmWidth * 24 + 31) / 32) * 4;
bitmap.bmPlanes = 1;
bitmap.bmBitsPixel = 24;
bitmap.bmBits = NULL;
const size_t length = bitmap.bmWidthBytes * bitmap.bmHeight;
auto buffer = (HANDLE)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, length);
RGBTRIPLE *bitmap_bits = (RGBTRIPLE *) GlobalLock((HGLOBAL) buffer);
register RGBTRIPLE *q = bitmap_bits;
for (size_t y = 0; y < image->image()->rows; y++)
{
register auto p = GetVirtualPixels(image->image(), 0, y, image->image()->columns, 1, exception);
if (!p) break;
for (size_t x = 0; x < image->image()->columns; x++)
{
q->rgbtRed = ScaleQuantumToChar(GetPixelRed(image->image(), p));
q->rgbtGreen = ScaleQuantumToChar(GetPixelGreen(image->image(), p));
q->rgbtBlue = ScaleQuantumToChar(GetPixelBlue(image->image(), p));
p += GetPixelChannels(image->image());
q++;
}
}
bitmap.bmBits = bitmap_bits;
HBITMAP hbmp = CreateBitmapIndirect(&bitmap);
But it seems that this code cannot produce valid bitmap. What am I doing wrong?
You are not taking the stride/alignment into account. Each row needs to be DWORD aligned.
Calculating Surface Stride
In an uncompressed bitmap, the stride is the number of bytes needed to go from the start of one row of pixels to the start of the next row. The image format defines a minimum stride for an image. In addition, the graphics hardware might require a larger stride for the surface that contains the image.
For uncompressed RGB formats, the minimum stride is always the image width in bytes, rounded up to the nearest DWORD. You can use the following formula to calculate the stride:
stride = ((((biWidth * biBitCount) + 31) & ~31) >> 3)
You need to fix the way you access the RGBTRIPLEs in the buffer.
Before the "x loop" you should do something like q = (RGBTRIPLE*) (((char*)bitmap_bits) + (y * bitmap.bmWidthBytes));
CreateBitmapIndirect creates a DDB which is perhaps not the best choice, create a DIB instead:
#define CalcStride(w, bpp) ( ((((w) * (bpp)) + 31) & ~31) >> 3 )
static void SetPixel24(UINT w, void*bits, UINT x, UINT y, COLORREF cr)
{
RGBTRIPLE*p = ((RGBTRIPLE*) ( ((char*)bits) + (y * CalcStride(w, 24)) )) + x;
p->rgbtRed = GetRValue(cr);
p->rgbtGreen = GetGValue(cr);
p->rgbtBlue = GetBValue(cr);
}
void Silly24BPPExample()
{
HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, WC_STATIC, 0, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_OVERLAPPEDWINDOW|SS_BITMAP|SS_REALSIZECONTROL, 0, 0, 99, 99, 0, 0, 0, 0);
const INT w = 4, h = 4, bpp = 24;
BITMAPINFO bi;
ZeroMemory(&bi, sizeof(bi));
BITMAPINFOHEADER&bih = bi.bmiHeader;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = w, bih.biHeight = -h;
bih.biPlanes = 1, bih.biBitCount = bpp;
bih.biCompression = BI_RGB;
void*bits;
HBITMAP hBmp = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &bits, NULL, 0);
for (UINT x = 0; x < w; ++x)
for (UINT y = 0; y < h; ++y)
SetPixel24(w, bits, x, y, RGB(255, 0, 0)); // All red
SetPixel24(w, bits, 0, 0, RGB(0, 0, 255)); // except one blue
SendMessage(hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hBmp);
for (MSG msg; IsWindow(hWnd) && GetMessage(&msg, 0, 0, 0); ) DispatchMessage(&msg);
// DeleteObject(...)
}

C++ convert 32 bit bmp image to 24 bit bmp and 16 bit bmp

Trying to convert 32 bit image B8R8G8A8 to 24bit image R8G8B8 and 16bit R5G5B5.
But result is very strange, maybe I do not understand how to convert image properly. How to do it properly and fix colors?
Input image:
After Convert32to16():
After Convert32to24():
stdafx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <windows.h>
// TODO: reference additional headers your program requires here
ImageConverter.cpp
#include "stdafx.h"
using std::cout;
using std::endl;
using std::ofstream;
using std::ifstream;
void Convert32to24(void* B8G8R8A8, BYTE* R8G8B8, int width, int height)
{
long B8G8R8A8Size = (width * height * 4);
long j = 0;
for (long i = 0; i < (B8G8R8A8Size - 3); i = i + 4)
{
BYTE Red = ((PBYTE)B8G8R8A8)[i + 2];
BYTE Green = ((PBYTE)B8G8R8A8)[i + 1];
BYTE Blue = ((PBYTE)B8G8R8A8)[i];
BYTE Alpha = ((PBYTE)B8G8R8A8)[i + 3];
R8G8B8[j] = Red;
R8G8B8[j + 1] = Green;
R8G8B8[j + 2] = Blue;
j = j + 3;
}
}
void Convert32to16(void* B8G8R8A8, BYTE* R5G5B5, int width, int height)
{
long B8G8R8A8Size = (width * height * 4);
long j = 0;
for (long i = 0; i < (B8G8R8A8Size - 3); i = i + 4)
{
BYTE Red = ((PBYTE)B8G8R8A8)[i + 2] >> 3;
BYTE Green = ((PBYTE)B8G8R8A8)[i + 1] >> 3;
BYTE Blue = ((PBYTE)B8G8R8A8)[i] >> 3;
BYTE Alpha = ((PBYTE)B8G8R8A8)[i + 3];
uint16_t RGB565 = ((Red >> 3) << 11) | ((Green >> 2) << 5) | (Blue >> 3);
R5G5B5[j] = RGB565 >> 8;
R5G5B5[j + 1] = RGB565 & 0xFF;
j = j + 2;
}
}
void WriteDataToBmp(const WCHAR *filename, void *imageData, int width, int height, int BitCount, int bytesPerPixel)
{
HANDLE hdl = INVALID_HANDLE_VALUE;
DWORD bytesWritten;
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER fileInfo;
fileInfo.biSize = sizeof(BITMAPINFOHEADER);
fileInfo.biBitCount = BitCount;
fileInfo.biCompression = BI_RGB;
fileInfo.biWidth = width;
fileInfo.biHeight = 0 - height;
fileInfo.biPlanes = 1;
fileInfo.biSizeImage = (width * height * bytesPerPixel);
fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + fileInfo.biSizeImage;
fileHeader.bfType = 'MB';
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
hdl = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hdl == INVALID_HANDLE_VALUE)
{
return;
}
WriteFile(hdl, &fileHeader, sizeof(fileHeader), &bytesWritten, NULL);
WriteFile(hdl, &fileInfo, sizeof(fileInfo), &bytesWritten, NULL);
WriteFile(hdl, imageData, fileInfo.biSizeImage, &bytesWritten, NULL);
CloseHandle(hdl);
}
unsigned char* ReadDataFromBmp(char* filename)
{
FILE* f = fopen(filename, "rb");
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f);
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int size = abs(4 * width * height);
unsigned char* data = new unsigned char[size];
fread(data, sizeof(unsigned char), size, f);
fclose(f);
return data;
}
int main(int args, char** cat) {
int width = 1440;
int height = 900;
int bytesOnPixel;
BYTE *OutputImage24Bit = new BYTE[width * height * 3];
BYTE *OutputImage16Bit = new BYTE[width * height * 2];
unsigned char* inputImage32Bit = ReadDataFromBmp((char*)"E:/TestImage.bmp");
bytesOnPixel = 2;
Convert32to16(inputImage32Bit, OutputImage16Bit, width, height);
WriteDataToBmp(L"E:/TestImage16bit.bmp", OutputImage16Bit, width, height, 8 * bytesOnPixel, bytesOnPixel);
bytesOnPixel = 3;
Convert32to24(inputImage32Bit, OutputImage24Bit, width, height);
WriteDataToBmp(L"E:/TestImage24bit.bmp", OutputImage24Bit, width, height, 8 * bytesOnPixel, bytesOnPixel);
return 1;
}
fileInfo.biCompression = BI_RGB;
16-bit bitmap uses BI_BITFIELDS compression. In addition 16-bit bitmap has to populate the color table to show if it is using 555 format, 565 format, or a different format.
24-bit and 16-bit bitmap need padding. Albeit, that's not an issue if the width in bytes is a multiple of 4. In general you cannot read/write pixel after pixel because the padding can throw everything off. Instead make 2 loops to go through the height and width. Pixel size would also depend on padding.
Note that you can do the same with or GDI+ or WIC. You can change the bitmap to different formats PixelFormat16bppRGB555, PixelFormat16bppRGB565, PixelFormat16bppARGB1555, PixelFormat24bppRGB...
GDI+ example:
int main()
{
Gdiplus::GdiplusStartupInput tmp;
ULONG_PTR token;
Gdiplus::GdiplusStartup(&token, &tmp, NULL);
auto *source = Gdiplus::Bitmap::FromFile(L"test.bmp");
auto *destination = source->Clone(0, 0, source->GetWidth(), source->GetHeight(),
PixelFormat16bppRGB565);
CLSID clsid_bmp;
CLSIDFromString(L"{557cf400-1a04-11d3-9a73-0000f81ef32e}", &clsid_bmp);
destination->Save(L"copy.bmp", &clsid_bmp);
delete destination;
delete source;
Gdiplus::GdiplusShutdown(token);
return 0;
}
Home made version: (using std::vector for memory, instead of new/delete)
void Convert32to24(const wchar_t* file, std::vector<BYTE> &src, int width, int height)
{
int width_in_bytes_32 = width * 4;
int width_in_bytes_24 = ((width * 24 + 31) / 32) * 4;
DWORD size = width_in_bytes_24 * height;
std::vector<BYTE> dst(size);
for(int h = 0; h < height; h++)
for(int w = 0; w < width; w++)
{
int i = h * width_in_bytes_32 + w * 4;
int j = h * width_in_bytes_24 + w * 3;
dst[j + 0] = src[i + 0];
dst[j + 1] = src[i + 1];
dst[j + 2] = src[i + 2];
}
BITMAPFILEHEADER bf = { 'MB', 54 + size, 0, 0, 54 };
BITMAPINFOHEADER bi = { sizeof(bi), width, height, 1, 24, BI_RGB };
std::ofstream fout(file, std::ios::binary);
fout.write((char*)&bf, sizeof(bf));
fout.write((char*)&bi, sizeof(bi));
fout.write((char*)&dst[0], size);
}
void Convert32to16(const wchar_t* file, std::vector<BYTE> &src, int width, int height)
{
int width_in_bytes_32 = width * 4;
int width_in_bytes_16 = ((width * 16 + 31) / 32) * 4;
DWORD size = width_in_bytes_16 * height;
std::vector<BYTE> dst(size);
for(int h = 0; h < height; h++)
for(int w = 0; w < width; w++)
{
int i = h * width_in_bytes_32 + w * 4;
int j = h * width_in_bytes_16 + w * 2;
//555 format, each color is from 0 to 32, instead of 0 to 256
uint16_t blu = (uint16_t)(src[i + 0] * 31.f / 255.f);
uint16_t grn = (uint16_t)(src[i + 1] * 31.f / 255.f);
uint16_t red = (uint16_t)(src[i + 2] * 31.f / 255.f);
uint16_t sum = (red) | (grn << 5) | (blu << 10);
memcpy(&dst[j], &sum, 2);
}
BITMAPFILEHEADER bf = { 'MB', 54 + size, 0, 0, 54 };
BITMAPINFOHEADER bi = { sizeof(bi), width, height, 1, 16, BI_BITFIELDS };
std::ofstream fout(file, std::ios::binary);
fout.write((char*)&bf, sizeof(bf));
fout.write((char*)&bi, sizeof(bi));
//555 format
COLORREF color[]{
0b0000000000011111,//31
0b0000001111100000,//31 << 5
0b0111110000000000 //31 << 10
};
fout.write((char*)&color, sizeof(color));
fout.write((char*)&dst[0], size);
}
int main()
{
const wchar_t* file_32 = L"E:\\TestImage.bmp";
const wchar_t* file_16 = L"E:\\OutputImage16Bit.bmp";
const wchar_t* file_24 = L"E:\\OutputImage24Bit.bmp";
BITMAPFILEHEADER bh;
BITMAPINFOHEADER bi;
std::ifstream fin(file_32, std::ios::binary);
if(!fin)
return 0;
fin.read((char*)&bh, sizeof(bh));
fin.read((char*)&bi, sizeof(bi));
if(bi.biBitCount != 32)
return 0;
std::vector<BYTE> source(bh.bfSize);
fin.read((char*)&source[0], bh.bfSize);
Convert32to16(file_16, source, bi.biWidth, bi.biHeight);
Convert32to24(file_24, source, bi.biWidth, bi.biHeight);
return 0;
}

Generating a sphere in OpenGL without high level libraries - what's wrong with my code?

I've tried to implement an inefficient function to generate the points, normals, tex coords, and index list of a sphere.
Ignoring the lines, when I draw the sphere with OpenGL I get the following output which is clearly wrong:
Can anyone help me understand what's wrong with my code?
public SphereObject()
{
super();
// inefficient but quick sphere data
int num_points = 16;
double as = Math.PI / num_points;
double theta, phi;
double [] p;
ArrayList<double []> points = new ArrayList<double []>();
ArrayList<Integer> edges = new ArrayList<Integer>();
ArrayList<double []> normals = new ArrayList<double []>();
ArrayList<double []> tex = new ArrayList<double []>();
theta = Math.PI;
phi = Math.PI / 2;
for(int row = 0; row < num_points; row++)
{
for(int col = 0; col < num_points; col++)
{
p = new double[3];
p[0] = Math.sin(theta) * Math.cos(phi - as);
p[1] = Math.cos(theta) * Math.cos(phi - as);
p[2] = Math.sin(phi - as);
points.add(p);
normals.add(p);
tex.add(new double [] {0, 0});
p = new double[3];
p[0] = Math.sin(theta + 2 * as) * Math.cos(phi - as);
p[1] = Math.cos(theta + 2 * as) * Math.cos(phi - as);
p[2] = Math.sin(phi - as);
points.add(p);
normals.add(p);
tex.add(new double [] {1, 0});
p = new double[3];
p[0] = Math.sin(theta + 2 * as) * Math.cos(phi);
p[1] = Math.cos(theta + 2 * as) * Math.cos(phi);
p[2] = Math.sin(phi);
points.add(p);
normals.add(p);
tex.add(new double [] {1, 1});
p = new double[3];
p[0] = Math.sin(theta) * Math.cos(phi);
p[1] = Math.cos(theta) * Math.cos(phi);
p[2] = Math.sin(phi);
points.add(p);
normals.add(p);
tex.add(new double [] {0, 1});
// make triangles
edges.add(points.size()-1);
edges.add(points.size()-3);
edges.add(points.size()-4);
edges.add(points.size()-1);
edges.add(points.size()-2);
edges.add(points.size()-3);
theta -= 2 * as;
}
phi -= as;
}
sphereVertices = new double[points.size() * 3];
sphereTexcoords = new double[tex.size() * 2];
sphereNormals = new double[normals.size() * 3];
sphereIndices = new short[edges.size() * 1];
for(int c1 = 0; c1 < points.size(); c1 += 3)
{
sphereVertices[c1] = points.get(c1)[0];
sphereVertices[c1+1] = points.get(c1)[1];
sphereVertices[c1+2] = points.get(c1)[2];
}
for(int c1 = 0; c1 < tex.size(); c1 += 2)
{
sphereTexcoords[c1] = tex.get(c1)[0];
sphereTexcoords[c1+1] = tex.get(c1)[1];
}
for(int c1 = 0; c1 < normals.size(); c1 += 3)
{
sphereNormals[c1] = normals.get(c1)[0];
sphereNormals[c1+1] = normals.get(c1)[1];
sphereNormals[c1+2] = normals.get(c1)[2];
}
for(int c1 = 0; c1 < edges.size(); c1++)
{
sphereIndices[c1] = edges.get(c1).shortValue();
}
mVertBuff = fillBuffer(sphereVertices);
mTexCoordBuff = fillBuffer(sphereTexcoords);
mNormBuff = fillBuffer(sphereNormals);
mIndBuff = fillBuffer(sphereIndices);
}
My OpenGL code is below. The getVertices() functions et al return the buffers created in the Sphere constructor above.
Matrix.translateM(modelViewMatrix, 0, 0, 0, kObjectScale);
Matrix.scaleM(modelViewMatrix, 0, kObjectScale, kObjectScale, kObjectScale);
GLES20.glUseProgram(shaderProgramID);
GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT, false, 0, sphere.getInstance().getVertices());
GLES20.glVertexAttribPointer(normalHandle, 3, GLES20.GL_FLOAT, false, 0, sphere.getInstance().getNormals());
GLES20.glVertexAttribPointer(textureCoordHandle, 2, GLES20.GL_FLOAT, false, 0, sphere.getInstance().getTexCoords());
GLES20.glEnableVertexAttribArray(vertexHandle);
GLES20.glEnableVertexAttribArray(normalHandle);
GLES20.glEnableVertexAttribArray(textureCoordHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures.get(2).mTextureID[0]);
Matrix.translateM(modelViewMatrix, 0, (float)result[0], (float)result[1], (float)result[2]);
Matrix.rotateM(modelViewMatrix, 0, 0, 1, 0, 0);
Matrix.rotateM(modelViewMatrix, 0, 0, 0, 1, 0);
Matrix.rotateM(modelViewMatrix, 0, 0, 0, 0, 1);
Matrix.scaleM(modelViewMatrix, 0, 5, 5, 5);
Matrix.multiplyMM(modelViewProjection, 0, vuforiaAppSession.getProjectionMatrix().getData(), 0, modelViewMatrix, 0);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, modelViewProjection, 0);
GLES20.glUniform1i(texSampler2DHandle, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, sphere.getInstance().getNumObjectIndex(), GLES20.GL_UNSIGNED_SHORT, sphere.getInstance().getIndices());
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDisableVertexAttribArray(vertexHandle);
GLES20.glDisableVertexAttribArray(normalHandle);
GLES20.glDisableVertexAttribArray(textureCoordHandle);
The fillBuffer code is as follows:
protected Buffer fillBuffer(double[] array)
{
// Convert to floats because OpenGL doesn't work on doubles, and manually
// casting each input value would take too much time.
// Each float takes 4 bytes
ByteBuffer bb = ByteBuffer.allocateDirect(4 * array.length);
bb.order(ByteOrder.LITTLE_ENDIAN);
for (double d : array)
bb.putFloat((float) d);
bb.rewind();
return bb;
}
The problem is when you add the points to the final arrays:
for(int c1 = 0; c1 < points.size(); c1 += 3)
{
sphereVertices[c1] = points.get(c1)[0];
sphereVertices[c1+1] = points.get(c1)[1];
sphereVertices[c1+2] = points.get(c1)[2];
}
instead of using the same index for both the array and the list us separate ones:
for(int c1 = 0, i= 0; c1 < points.size(); c1++)
{
sphereVertices[i++] = points.get(c1)[0];
sphereVertices[i++] = points.get(c1)[1];
sphereVertices[i++] = points.get(c1)[2];
}
same for the other arrays

Optical Flow OpenCV "lkpyramid.cpp" throws exception

I am trying to use calcOpticalFlowPyrLK function of openCV for motion detection but I am getting error message :
OpenCV Error: Assertion failed ((npoints = prevPtsMat.checkVector(2, CV_32F, tru
e)) >= 0) in cv::calcOpticalFlowPyrLK, file ..\..\..\..\opencv\modules\video\src
\lkpyramid.cpp, line 845
I have checked that the previous corners stored in corners1 of my code is not empty and are valid points."goodFeaturesToTrack" function works fine.
I have been stuck here for 2 days any help would be appreciated.
Code Block:
int opticalflow()
{
Mat frame1, frame2, frame3, difference1, difference2, frame, mask;
VideoCapture capture;
vector <Point2d> corners1;
vector <Point2d> corners2;
int maxCorners = 200;
double qualityLevel = 0.01;
double minDistance = 5;
int blockSize = 3;
bool useHarrisDetector = false;
double k = 0.04;
vector <unsigned char> optical_flow_found_feature;
vector <float > optical_flow_feature_error;
//Read the video stream
capture.open(0);
if (!capture.isOpened())
{
printf("Error Opening Video Capture!!!\n");
}
waitKey(10);
capture.read(frame1);
cvtColor( frame1, frame1, COLOR_BGR2GRAY );
goodFeaturesToTrack( frame1, corners1, maxCorners, qualityLevel, minDistance, mask, blockSize, useHarrisDetector, k );
for(int i=0; i<corners1.size(); i++)
cout<<corners1[i].x<<" "<<corners1[i].y<<endl;
while (1)
{
capture.read(frame2);
cvtColor( frame2, frame2, COLOR_BGR2GRAY );
if(corners1.size()>10)
calcOpticalFlowPyrLK(frame1, frame2, corners1, corners2, optical_flow_found_feature, optical_flow_feature_error);// Size(21,21), 3, TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), 0, 1e-4);
cout<<"Reached Here\n";
for(int i=0; i<maxCorners; i++)
{
if(optical_flow_found_feature[i] == 0)
continue;
int line_thickness = 1;
CvScalar line_color = CV_RGB(255,0,0);
Point2d p,q;
p.x = (int) corners1[i].x;
p.y = (int) corners1[i].y;
q.x = (int) corners2[i].x;
q.y = (int) corners2[i].y;
double angle = atan2( (double) p.y - q.y, (double) p.x - q.x );
double hypotenuse = sqrt((long double)(p.y - q.y)*(p.y - q.y) + (p.x - q.x)*(p.x - q.x) );
q.x = (int) (p.x - 3 * hypotenuse * cos(angle));
q.y = (int) (p.y - 3 * hypotenuse * sin(angle));
line( frame1, p, q, line_color, line_thickness, CV_AA, 0 );
p.x = (int) (q.x + 9 * cos(angle + pi / 4));
p.y = (int) (q.y + 9 * sin(angle + pi / 4));
line( frame1, p, q, line_color, line_thickness, CV_AA, 0 );
p.x = (int) (q.x + 9 * cos(angle - pi / 4));
p.y = (int) (q.y + 9 * sin(angle - pi / 4));
line( frame1, p, q, line_color, line_thickness, CV_AA, 0 );
}
display(frame1);
int c = waitKey(25);
//Exit if escape is pressed
if((char)c == 27)
{
break;
}
}
return 0;
}
Platform:
I am using Visual Studio 2010
OpenCV 2.4.9
on Windows 8

Resources