OpenCL can not detect my nVidia GPU via OpenCV - opencv

I have two GPUs : Intel HD and nVidia Quadro. Using GPU Caps Viewer, I can detect my both GPUs in the OpenCL tab. However, by executing this code I am only getting the Intel one:
cv::ocl::setUseOpenCL(true);
if (!cv::ocl::haveOpenCL()) {
std::cout << "OpenCL is not available..." << std::endl;
}
cv::ocl::Context context;
if (!context.create(cv::ocl::Device::TYPE_ALL)) {
std::cout << "Failed creating the context..." << std::endl;
}
std::cout << context.ndevices() << " GPU devices are detected." << std::endl;
for (int i = 0; i < context.ndevices(); i++) {
cv::ocl::Device device = context.device(i);
std::cout << "name: " << device.name() << std::endl;
std::cout << "available: " << device.available() << std::endl;
std::cout << "imageSupport: " << device.imageSupport() << std::endl;
std::cout << "OpenCL_C_Version: " << device.OpenCL_C_Version() << std::endl;
std::cout << std::endl;
}
Results:
1 GPU devices are detected.
name: Intel(R) HD Graphics P530
available: 1
imageSupport: 1
OpenCL_C_Version: OpenCL C 2.0
Information:
Windows 10
OpenCV 3.1
Visual studio 2013
nVidia Quadro M4000M
Notes:
I am able to call my nVidia GPU directly using the OpenCV Cuda Interface.
I have just installed the latest driver from nVidia website.

The solution in my case was to add this environment variable:
OPENCV_OPENCL_DEVICE=NVIDIA:GPU:

Related

Can't display image in Visual Studio 2015

Here's my code:
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat image;
cout << "This image has " << image.rows <<" rows and "<<image.cols<<" columns"<< endl;
image = imread("images.jpg");
if (image.empty()) {
cout << "Image not read properly" << endl;
getchar();
return 0;
}
cout << "The size of the image is " << image.rows << " rows and " << image.cols << " columns." << endl;
cout << "This image has " << image.channels() << " channels." << endl;
namedWindow("Original_Image",CV_WINDOW_AUTOSIZE);
imshow("Original_Image", image);
waitKey(0);
return 0;
}
The window which should display the image is just blank. I'm using Visual Studio 2015, OpenCV 3.2.0.
You might get a blank image if the path of the image is wrong. The blank window is given by the namedWindow statement, which just creates the window. Try giving the full path of the image in imread(eg if your image is saved under Downloads, use the file path as "C:\\Users\\name\\Downloads\\image.jpg"). Be sure to use double back slashes while specifying the file path(forward slash in linux based systems and back slash in windows!!).

Cuda, unified memory, data transfers

Does cuda somehow block and transfer all allocated managed memory to the GPU when a kernel is launched? I just played with uma and got strange results. At least in my point of view.
I created 2 arrays and send A to kernel, B is untouched by kernel call but it cannot be accessed. The program just crashes when I touch B.
0 0 0 here1
If I comment out the b[0] = 1; line the code runs fine:
0 0 0 here1 after1 0 here2 1 after2
Why is this happening ?
__global__ void kernel(int* t)
{
t[0]++;
}
int main()
{
int* a;
int* b;
std::cout << cudaMallocManaged(&a,sizeof(int)*100) << std::endl;
std::cout << cudaMallocManaged(&b,sizeof(int)*100) << std::endl;
std::cout << b[0] << std::endl;
kernel<<<1,1,0,0>>>(a);
std::cout << "here1" << std::endl;
b[0] = 1;
std::cout << "after1" << std::endl;
cudaDeviceSynchronize();
std::cout << b[0] << std::endl;
std::cout << "here2" << std::endl;
std::cout << a[0] << std::endl;
std::cout << "after2" << std::endl;
return 0;
}
Does cuda somehow block and transfer all allocated managed memory to
the GPU when a kernel is launched?
Yes, provided your device is of compute capability less than 6.0.
On these devices managed memory works by copying all managed memory to the GPU before kernel launch, and copying all managed memory back to the host on synchronization. During that timespan, accessing managed memory from the host will lead to a segmentation fault.
You can be more specific about which memory to copy for a given kernel by attaching it to a stream using cudaStreamAttachMemAsync() and launching the kernel into that stream.

How can I change the device on which OpenCL-code will be executed with Umat in OpenCV?

As known, OpenCV 3.0 supports new class cv::Umat which provides Transparent API (TAPI) to use OpenCL automaticaly if it can: http://code.opencv.org/projects/opencv/wiki/Opencv3#tapi
There are two introductions to the cv::Umat and TAPI:
Intel: https://software.intel.com/en-us/articles/opencv-30-architecture-guide-for-intel-inde-opencv
AMD: http://developer.amd.com/community/blog/2014/10/15/opencv-3-0-transparent-api-opencl-acceleration/
But if I have:
Intel CPU Core i5 (Haswell) 4xCores (OpenCL Intel CPUs with SSE 4.1, SSE 4.2 or AVX support)
Intel Integrated HD Graphics which supports OpenCL 1.2
1st nVidia GPU GeForce GTX 970 (Maxwell) which supports OpenCL 1.2
and CUDA
2nd nVidia GPU GeForce GTX 970 ...
If I turn on OpenCL in OpenCV, then how can I change the device on which OpenCL-code will be executed: on 8 Cores of CPU, on Integrated HD Graphics, on 1st nVidia GPU or 2nd nVidia GPU?
How can I select one of each of these 4 devices to use OpenCL for parallel execution algorithms with cv::Umat?
For example, how can I use OpenCL acceleration on 4xCores of CPU Core-i5 with cv::Umat?
I use something like this to check versions and hardware being used for OpenCL support.
ocl::setUseOpenCL(true);
if (!ocl::haveOpenCL())
{
cout << "OpenCL is not available..." << endl;
//return;
}
cv::ocl::Context context;
if (!context.create(cv::ocl::Device::TYPE_GPU))
{
cout << "Failed creating the context..." << endl;
//return;
}
cout << context.ndevices() << " GPU devices are detected." << endl; //This bit provides an overview of the OpenCL devices you have in your computer
for (int i = 0; i < context.ndevices(); i++)
{
cv::ocl::Device device = context.device(i);
cout << "name: " << device.name() << endl;
cout << "available: " << device.available() << endl;
cout << "imageSupport: " << device.imageSupport() << endl;
cout << "OpenCL_C_Version: " << device.OpenCL_C_Version() << endl;
cout << endl;
}
Then you can set your preferred hardware to use, using this
cv::ocl::Device(context.device(1));
Hope this helps you.
You can also set a desired OpenCL device from within your code using environment variable method as follows (example is first GPU device):
if (putenv("OPENCV_OPENCL_DEVICE=:GPU:0") != 0 || !cv::ocl::useOpenCL())
{
std::cerr << "Failed to set a desired OpenCL device" << std::endl;
std::cerr << "Press any key to exit..." << std::endl;
getchar();
return 1;
}
Call to cv::ocl::useOpenCL() will force OpenCV to setup a default OpenCL device to the one specified in the environment variable OPENCV_OPENCL_DEVICE which is setup prior to that call.
I checked that this actually happens by setting a break-point at opencv_core310d.dll!cv::ocl::selectOpenCLDevice() Line 2256 (opencv\source\modules\core\src\ocl.cpp):
static cl_device_id selectOpenCLDevice()
{
std::string platform, deviceName;
std::vector<std::string> deviceTypes;
const char* configuration = getenv("OPENCV_OPENCL_DEVICE");
if (configuration &&
(strcmp(configuration, "disabled") == 0 ||
!parseOpenCLDeviceConfiguration(std::string(configuration), platform, deviceTypes, deviceName)
))
return NULL;

OpenCV 3.0 with OpenCL 2.0, each respond with different versions for OpenCL

I recently upgraded to a GPU card with OpenCL 2.0 (R9 390), from one with only OpenCL 1.2 on it. To start using it with OpenCV I created some basic calls to determine what hardware each library thought I had.
cout << "Equipment according to OpenCV:" << endl;
//Setup OpenCV first
cv::ocl::setUseOpenCL(true);
//OpenCV: Platform Info
std::vector<cv::ocl::PlatformInfo> platforms;
cv::ocl::getPlatfomsInfo(platforms);
//OpenCV Platforms
for (size_t i = 0; i < platforms.size(); i++)
{
const cv::ocl::PlatformInfo* platform = &platforms[i];
//Platform Name
std::cout << "Platform Name: " << platform->name().c_str() << "\n";
//Access known device
cv::ocl::Device current_device;
for (int j = 0; j < platform->deviceNumber(); j++)
{
//Access Device
platform->getDevice(current_device, j);
std::cout << "Device Name: " << current_device.name().c_str() << "\n";
}
}
cv::ocl::Device(current_device); // Required?
cout << cvContext.ndevices() << " GPU devices are detected." << endl;
for (int i = 0; i < cvContext.ndevices(); i++)
{
cv::ocl::Device device = cvContext.device(i);
cout << "name: " << device.name() << endl;
cout << "available: " << device.available() << endl;
cout << "imageSupport: " << device.imageSupport() << endl;
cout << "OpenCL_C_Version: " << device.OpenCL_C_Version() << endl;
cout << "Use OpenCL: " << cv::ocl::useOpenCL() << endl;
cout << endl;
}
cv::ocl::Device(cvContext.device(0)); //Here is where you change which GPU to use (e.g. 0 or 1)
// Setup OpenCL
cout << "Equipment according to OpenCL:" << endl;
vector<cl::Platform> clPlatforms;
vector<cl::Device> clPlatformDevices, clAllDevices;//, clCTXdevices;
string clPlatform_name, clDevice_name;
cl_uint i;
cl::Platform::get(&clPlatforms);
for(i=0; i<clPlatforms.size();i++)
{
clPlatform_name = clPlatforms[i].getInfo<CL_PLATFORM_NAME>();
cout<< "Platform: " <<clPlatform_name.c_str()<<endl;
clPlatforms[i].getDevices(CL_DEVICE_TYPE_ALL, &clPlatformDevices);
// Create context and access device names
clContext = cl::Context(clPlatformDevices);
clCTXdevices = clContext.getInfo<CL_CONTEXT_DEVICES>();
for(i=0; i<clCTXdevices.size(); i++) {
clDevice_name = clCTXdevices[i].getInfo<CL_DEVICE_NAME>();
cout << "Device: " << clDevice_name.c_str() << endl;
}
}
cout << "OpenCL Version: "<<clPlatforms[0].getInfo<CL_PLATFORM_VERSION>().c_str() <<endl;
cout << "Vendor: "<<clPlatforms[0].getInfo<CL_PLATFORM_VENDOR>().c_str() <<endl;
cout << "Extensions: "<<clPlatforms[0].getInfo<CL_PLATFORM_EXTENSIONS>().c_str() <<endl;
and the output:
Equipment according to OpenCV:
Platform Name: AMD Accelerated Parallel Processing
Device Name: Hawaii
Device Name: Intel(R) Core(TM)2 Quad CPU Q9450 # 2.66GHz
1 GPU devices are detected.
name: Hawaii
available: 1
imageSupport: 1
OpenCL_C_Version: OpenCL C 1.2
Use OpenCL: 1
Equipment according to OpenCL:
Platform: AMD Accelerated Parallel Processing
Device: Hawaii
Device: Intel(R) Core(TM)2 Quad CPU Q9450 # 2.66GHz
OpenCL Version: OpenCL 2.0 AMD-APP (1729.3)
Vendor: Advanced Micro Devices, Inc.
Extensions: cl_khr_icd cl_amd_event_callback cl_amd_offline_devices
So OpenCV thinks I have OpenCL 1.2, while OpenCL is a little smarter and returns 2.0...
Any ideas why they would not return the same version of OpenCL? I'm wondering if I need to re-compile OpenCV so it can recognize that there is a newer version of OpenCL available to it? Is OpenCV 3.0 limited to using OpenCL 1.2 calls?
Thanks!
I started completely over and used Ubuntu 14.04 64-bit instead. Now when I run the same code, the OpenCV library does indeed recognize the GPU as OpenCL 2.0

OpenCV directshow camera access results in black image unless the camera has been opened previously from other software

An analog framegrabber's image can be read via OpenCV only after the demo-application has opened the grabber, otherwise a black image results.
The following debug code
qDebug() << "Brightness" << cap->get(CV_CAP_PROP_BRIGHTNESS);
qDebug() << "Contrast " << cap->get(CV_CAP_PROP_CONTRAST);
qDebug() << "Saturation" << cap->get(CV_CAP_PROP_SATURATION);
qDebug() << "Hue " << cap->get(CV_CAP_PROP_HUE);
qDebug() << "Gain " << cap->get(CV_CAP_PROP_GAIN);
qDebug() << "Exposure " << cap->get(CV_CAP_PROP_EXPOSURE);
qDebug() << "Width " << cap->get(CV_CAP_PROP_FRAME_WIDTH);
qDebug() << "Height " << cap->get(CV_CAP_PROP_FRAME_HEIGHT);
outputs
Brightness 5000
Contrast 5000
Saturation 4000
Hue 5000
Gain -8.58993e+08
Exposure -1
Width 720
Height 576
Of course these settings seem defective, but they are the same when opening the device successfully after it has been accessed by the grabber's demo application.
I suppose this is a driver issue where certain device settings are required that OpenCV cannot access, including invalid standard settings (gain, exposure). What lower-level methods could be used to find out about / write those settings?
It seems that camera actually did not load yet and OpenCV already tries to take the image.
For me querying couple of more frames usually helps, like this:
CvCapture* capture = cvCaptureFromCAM( CV_CAP_ANY );
if ( capture ) {
IplImage* frame = cvQueryFrame( capture );
for (int i = 0; i < `0; i++)
{
frame = cvQueryFrame(capture);
}
cvSaveImage("mypic.jpg",frame);
cvReleaseCapture( &capture );
}

Resources