There having these two ways to open the camera cv::VideoCapture:
CV_WRAP virtual bool open(const String& filename)
CV_WRAP virtual bool open(int index)
Is possible open the camera using the index and get the filename(device name) from the VideoCapture object?
or How to find the device name of a USB webcam in Windows which pass to open function?
From my knowledge, OpenCV does not provide such functionality. To get the names of the attached devices, you'll need to go lower and use the DirectShow or WMF API to get the device enumeration list.
Here is a good answer which will help you to do what you want, but not with OpenCV. Pasting the same code from the post.
#pragma once
#include <new>
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <Wmcodecdsp.h>
#include <assert.h>
#include <Dbt.h>
#include <shlwapi.h>
#include <mfplay.h>
#include <iostream>
const UINT WM_APP_PREVIEW_ERROR = WM_APP + 1; // wparam = HRESULT
class DeviceList
{
UINT32 m_cDevices; // contains the number of devices
IMFActivate **m_ppDevices; // contains properties about each device
public:
DeviceList() : m_ppDevices(NULL), m_cDevices(0)
{
MFStartup(MF_VERSION);
}
~DeviceList()
{
Clear();
}
UINT32 Count() const { return m_cDevices; }
void Clear();
HRESULT EnumerateDevices();
HRESULT GetDevice(UINT32 index, IMFActivate **ppActivate);
HRESULT GetDeviceName(UINT32 index, WCHAR **ppszName);
};
#include "DeviceList.h"
/*
* A templated Function SafeRelease releasing pointers memories
* #param ppT the pointer to release
*/
template <class T> void SafeRelease(T **ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
/*
* A function which copy attribute form source to a destination
* # param pSrc is an Interface to store key/value pairs of an Object
* # param pDest is an Interface to store key/value pairs of an Object
* # param GUID is an unique identifier
* # return HRESULT return errors warning condition on windows
*/
HRESULT CopyAttribute(IMFAttributes *pSrc, IMFAttributes *pDest, const GUID& key);
/*
* A Method form DeviceList which clear the list of Devices
*/
void DeviceList::Clear()
{
for (UINT32 i = 0; i < m_cDevices; i++)
{
SafeRelease(&m_ppDevices[i]);
}
CoTaskMemFree(m_ppDevices);
m_ppDevices = NULL;
m_cDevices = 0;
}
/*
* A function which enumerate the list of Devices.
* # return HRESULT return errors warning condition on windows
*/
HRESULT DeviceList::EnumerateDevices()
{
HRESULT hr = S_OK;
IMFAttributes *pAttributes = NULL;
this->Clear();
// Initialize an attribute store. We will use this to
// specify the enumeration parameters.
std::cout << "Enumerate devices" << std::endl;
hr = MFCreateAttributes(&pAttributes, 1);
// Ask for source type = video capture devices
if (SUCCEEDED(hr))
{
std::cout << "Enumerate devices" << std::endl;
hr = pAttributes->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
);
}
// Enumerate devices.
if (SUCCEEDED(hr))
{
std::cout << "Enumerate devices:" << m_cDevices << std::endl;
hr = MFEnumDeviceSources(pAttributes, &m_ppDevices, &m_cDevices);
}
SafeRelease(&pAttributes);
return hr;
}
/*
* A function which copy attribute form source to a destination
* # param index the index in an array
* # param ppActivate is an Interface to store key/value pairs of an Object
* # return HRESULT return errors warning condition on windows
*/
HRESULT DeviceList::GetDevice(UINT32 index, IMFActivate **ppActivate)
{
if (index >= Count())
{
return E_INVALIDARG;
}
*ppActivate = m_ppDevices[index];
(*ppActivate)->AddRef();
return S_OK;
}
/*
* A function which get the name of the devices
* # param index the index in an array
* # param ppszName Name of the device
*/
HRESULT DeviceList::GetDeviceName(UINT32 index, WCHAR **ppszName)
{
std::cout << "Get Device name" << std::endl;
if (index >= Count())
{
return E_INVALIDARG;
}
HRESULT hr = S_OK;
hr = m_ppDevices[index]->GetAllocatedString(
MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
ppszName,
NULL
);
return hr;
}
#include <iostream>
#include "DeviceList.h"
HRESULT UpdateDeviceList()
{
HRESULT hr = S_OK;
WCHAR *szFriendlyName = NULL;
DeviceList g_devices;
g_devices.Clear();
hr = g_devices.EnumerateDevices();
if (FAILED(hr)) { goto done; }
std::cout << "Nb devices found:"<< g_devices.Count() << std::endl;
for (UINT32 iDevice = 0; iDevice < g_devices.Count(); iDevice++)
{
//std::cout << "" << std::endl;
hr = g_devices.GetDeviceName(iDevice, &szFriendlyName);
if (FAILED(hr)) { goto done; }
std::cout << szFriendlyName << std::endl;
// The list might be sorted, so the list index is not always the same as the
// array index. Therefore, set the array index as item data.
CoTaskMemFree(szFriendlyName);
szFriendlyName = NULL;
}
std::cout << "End of EnumDeviceList" << std::endl;
done:
return hr;
}
int main()
{
std::cout <<"Main" << std::endl;
UpdateDeviceList();
while (1);
return 0;
}
This is more close to what you want(Note that, all STRING types are std::string):
int _GetUSBCameraDevicesList(std::vector<__STRING__>& list, std::vector<__STRING__>& devicePaths)
{
//COM Library Initialization
//comInit();
ICreateDevEnum* pDevEnum = NULL;
IEnumMoniker* pEnum = NULL;
int deviceCounter = 0;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
reinterpret_cast<void**>(&pDevEnum));
if (SUCCEEDED(hr))
{
// Create an enumerator for the video capture category.
hr = pDevEnum->CreateClassEnumerator(
CLSID_VideoInputDeviceCategory,
&pEnum, 0);
if (hr == S_OK) {
printf("SETUP: Looking For Capture Devices\n");
IMoniker* pMoniker = NULL;
while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void**)(&pPropBag));
if (FAILED(hr)) {
pMoniker->Release();
continue; // Skip this one, maybe the next one will work.
}
// Find the description or friendly name.
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"Description", &varName, 0);
if (FAILED(hr)) hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
int count = 0;
char tmp[255] = { 0 };
//int maxLen = sizeof(deviceNames[0]) / sizeof(deviceNames[0][0]) - 2;
while (varName.bstrVal[count] != 0x00 && count < 255)
{
tmp[count] = (char)varName.bstrVal[count];
count++;
}
list.emplace_back(tmp);
//deviceNames[deviceCounter][count] = 0;
//if (!silent) DebugPrintOut("SETUP: %i) %s\n", deviceCounter, deviceNames[deviceCounter]);
// then read Device Path
{
VARIANT DP_Path;
VariantInit(&DP_Path);
hr = pPropBag->Read(L"DevicePath", &DP_Path, 0);
if (SUCCEEDED(hr))
{
int __count = 0;
char __tmp[255] = { 0 };
while (DP_Path.bstrVal[__count] != 0x00 && __count < 255)
{
__tmp[__count] = (char)DP_Path.bstrVal[__count];
__count++;
}
devicePaths.emplace_back(__tmp);
}
}
}
pPropBag->Release();
pPropBag = NULL;
pMoniker->Release();
pMoniker = NULL;
deviceCounter++;
}
pDevEnum->Release();
pDevEnum = NULL;
pEnum->Release();
pEnum = NULL;
}
//if (!silent) DebugPrintOut("SETUP: %i Device(s) found\n\n", deviceCounter);
}
//comUnInit();
return deviceCounter;
}
Just pass two std::vectorstd::string() to get the list of all connected devices and their paths(Paths may be used to compare device identity if two device have the same friendly name).
Related
I have some generated SPIR-V code which I want to use with the vulkan API. But I get an
Exception thrown at 0x00007FFB68D933CB (nvoglv64.dll) in vulkanCompute.exe: 0xC0000005: Access violation reading location 0x0000000000000008. when trying to create the pipline with vkCreateComputePipelines.
The API calls should be fine, because the same code works with a shader compiled with glslangValidator. Therefore I assume that the generated SPIR-V code must be illformed somehow.
I've checked the SPIR-V code with the validator tool from khronos, using spirv-val --target-env vulkan1.1 mainV.spv which exited without error. Anyhow it is also known that this tool is still incomplete.
I've also tried to use the Radeon GPU Analyzer to compile my SPIR-V code, which is also available online at the shader playground and this tool throws the error Error: Error: internal error: Bil::BilInstructionConvert::Create(60) Code Not Tested! which is not really helpful, but encourages the assumption that the code is malformed.
The SPIR-V code is unfortunately to long to post it here, but it is in the link of the shader playground.
Does anyone know what the problem is with my setting or has any idea how I can verify my SPIR-V code in a better way, without checking all 700 lines of code manually.
I don't thinkt the problem is there, but anyway here is the c++ host code:
#include "vulkan/vulkan.hpp"
#include <iostream>
#include <fstream>
#include <vector>
#define BAIL_ON_BAD_RESULT(result) \
if (VK_SUCCESS != (result)) \
{ \
fprintf(stderr, "Failure at %u %s\n", __LINE__, __FILE__); \
exit(-1); \
}
VkResult vkGetBestComputeQueueNPH(vk::PhysicalDevice &physicalDevice, uint32_t &queueFamilyIndex)
{
auto properties = physicalDevice.getQueueFamilyProperties();
int i = 0;
for (auto prop : properties)
{
vk::QueueFlags maskedFlags = (~(vk::QueueFlagBits::eTransfer | vk::QueueFlagBits::eSparseBinding) & prop.queueFlags);
if (!(vk::QueueFlagBits::eGraphics & maskedFlags) && (vk::QueueFlagBits::eCompute & maskedFlags))
{
queueFamilyIndex = i;
return VK_SUCCESS;
}
i++;
}
i = 0;
for (auto prop : properties)
{
vk::QueueFlags maskedFlags = (~(vk::QueueFlagBits::eTransfer | vk::QueueFlagBits::eSparseBinding) & prop.queueFlags);
if (vk::QueueFlagBits::eCompute & maskedFlags)
{
queueFamilyIndex = i;
return VK_SUCCESS;
}
i++;
}
return VK_ERROR_INITIALIZATION_FAILED;
}
int main(int argc, const char *const argv[])
{
(void)argc;
(void)argv;
try
{
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo("VecAdd", 1, "Vulkan.hpp", 1, VK_API_VERSION_1_1);
// initialize the vk::InstanceCreateInfo
std::vector<char *> layers = {
"VK_LAYER_LUNARG_api_dump",
"VK_LAYER_KHRONOS_validation"
};
vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo, static_cast<uint32_t>(layers.size()), layers.data());
// create a UniqueInstance
vk::UniqueInstance instance = vk::createInstanceUnique(instanceCreateInfo);
auto physicalDevices = instance->enumeratePhysicalDevices();
for (auto &physicalDevice : physicalDevices)
{
auto props = physicalDevice.getProperties();
// get the QueueFamilyProperties of the first PhysicalDevice
std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties();
uint32_t computeQueueFamilyIndex = 0;
// get the best index into queueFamiliyProperties which supports compute and stuff
BAIL_ON_BAD_RESULT(vkGetBestComputeQueueNPH(physicalDevice, computeQueueFamilyIndex));
std::vector<char *>extensions = {"VK_EXT_external_memory_host", "VK_KHR_shader_float16_int8"};
// create a UniqueDevice
float queuePriority = 0.0f;
vk::DeviceQueueCreateInfo deviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), static_cast<uint32_t>(computeQueueFamilyIndex), 1, &queuePriority);
vk::StructureChain<vk::DeviceCreateInfo, vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceShaderFloat16Int8Features> createDeviceInfo = {
vk::DeviceCreateInfo(vk::DeviceCreateFlags(), 1, &deviceQueueCreateInfo, 0, nullptr, static_cast<uint32_t>(extensions.size()), extensions.data()),
vk::PhysicalDeviceFeatures2(),
vk::PhysicalDeviceShaderFloat16Int8Features()
};
createDeviceInfo.get<vk::PhysicalDeviceFeatures2>().features.setShaderInt64(true);
createDeviceInfo.get<vk::PhysicalDeviceShaderFloat16Int8Features>().setShaderInt8(true);
vk::UniqueDevice device = physicalDevice.createDeviceUnique(createDeviceInfo.get<vk::DeviceCreateInfo>());
auto memoryProperties2 = physicalDevice.getMemoryProperties2();
vk::PhysicalDeviceMemoryProperties const &memoryProperties = memoryProperties2.memoryProperties;
const int32_t bufferLength = 16384;
const uint32_t bufferSize = sizeof(int32_t) * bufferLength;
// we are going to need two buffers from this one memory
const vk::DeviceSize memorySize = bufferSize * 3;
// set memoryTypeIndex to an invalid entry in the properties.memoryTypes array
uint32_t memoryTypeIndex = VK_MAX_MEMORY_TYPES;
for (uint32_t k = 0; k < memoryProperties.memoryTypeCount; k++)
{
if ((vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent) & memoryProperties.memoryTypes[k].propertyFlags &&
(memorySize < memoryProperties.memoryHeaps[memoryProperties.memoryTypes[k].heapIndex].size))
{
memoryTypeIndex = k;
std::cout << "found memory " << memoryTypeIndex + 1 << " out of " << memoryProperties.memoryTypeCount << std::endl;
break;
}
}
BAIL_ON_BAD_RESULT(memoryTypeIndex == VK_MAX_MEMORY_TYPES ? VK_ERROR_OUT_OF_HOST_MEMORY : VK_SUCCESS);
auto memory = device->allocateMemoryUnique(vk::MemoryAllocateInfo(memorySize, memoryTypeIndex));
auto in_buffer = device->createBufferUnique(vk::BufferCreateInfo(vk::BufferCreateFlags(), bufferSize, vk::BufferUsageFlagBits::eStorageBuffer, vk::SharingMode::eExclusive));
device->bindBufferMemory(in_buffer.get(), memory.get(), 0);
// create a DescriptorSetLayout
std::vector<vk::DescriptorSetLayoutBinding> descriptorSetLayoutBinding{
{0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute}};
vk::UniqueDescriptorSetLayout descriptorSetLayout = device->createDescriptorSetLayoutUnique(vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), static_cast<uint32_t>(descriptorSetLayoutBinding.size()), descriptorSetLayoutBinding.data()));
std::cout << "Memory bound" << std::endl;
std::ifstream myfile;
myfile.open("shaders/MainV.spv", std::ios::ate | std::ios::binary);
if (!myfile.is_open())
{
std::cout << "File not found" << std::endl;
return EXIT_FAILURE;
}
auto size = myfile.tellg();
std::vector<unsigned int> shader_spv(size / sizeof(unsigned int));
myfile.seekg(0);
myfile.read(reinterpret_cast<char *>(shader_spv.data()), size);
myfile.close();
std::cout << "Shader size: " << shader_spv.size() << std::endl;
auto shaderModule = device->createShaderModuleUnique(vk::ShaderModuleCreateInfo(vk::ShaderModuleCreateFlags(), shader_spv.size() * sizeof(unsigned int), shader_spv.data()));
// create a PipelineLayout using that DescriptorSetLayout
vk::UniquePipelineLayout pipelineLayout = device->createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descriptorSetLayout.get()));
vk::ComputePipelineCreateInfo computePipelineInfo(
vk::PipelineCreateFlags(),
vk::PipelineShaderStageCreateInfo(
vk::PipelineShaderStageCreateFlags(),
vk::ShaderStageFlagBits::eCompute,
shaderModule.get(),
"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE6VecAdd"),
pipelineLayout.get());
auto pipeline = device->createComputePipelineUnique(nullptr, computePipelineInfo);
auto descriptorPoolSize = vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 2);
auto descriptorPool = device->createDescriptorPool(vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlags(), 1, 1, &descriptorPoolSize));
auto commandPool = device->createCommandPoolUnique(vk::CommandPoolCreateInfo(vk::CommandPoolCreateFlags(), computeQueueFamilyIndex));
auto commandBuffer = std::move(device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1)).front());
commandBuffer->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)));
commandBuffer->bindPipeline(vk::PipelineBindPoint::eCompute, pipeline.get());
commandBuffer->dispatch(bufferSize / sizeof(int32_t), 1, 1);
commandBuffer->end();
auto queue = device->getQueue(computeQueueFamilyIndex, 0);
vk::SubmitInfo submitInfo(0, nullptr, nullptr, 1, &commandBuffer.get(), 0, nullptr);
queue.submit(1, &submitInfo, vk::Fence());
queue.waitIdle();
printf("all done\nWoohooo!!!\n\n");
}
}
catch (vk::SystemError &err)
{
std::cout << "vk::SystemError: " << err.what() << std::endl;
exit(-1);
}
catch (std::runtime_error &err)
{
std::cout << "std::runtime_error: " << err.what() << std::endl;
exit(-1);
}
catch (...)
{
std::cout << "unknown error\n";
exit(-1);
}
return EXIT_SUCCESS;
}
Well after checking out line per line it showed that the problem is when working with pointers of pointers. For me it is still not clear from the specification that it is not allowed, but it is understandable that it does not work with logical pointers.
Still the behaviour is strange that the validator is not able to note that and that compiling the SPIRV code crashes instead of throwing a clear error message.
So in the end, it was the Shader code which was wrong.
I'm using the autowrap function to interact with VBA and now I get the control using item method as below.
VARIANT result;
VariantInit(&result);
VARIANT x;
x.vt = VT_INT;
x.intVal = index;
wchar_t method[] = L"Item";
hr = AutoWrap(DISPATCH_METHOD, &result, pControls, method,1,x);
pObject = result.pdispVal;
I can get the name of the control item using this code below:
VARIANT result;
VariantInit(&result);
wchar_t method[] = L"Name";
hr = AutoWrap(DISPATCH_PROPERTYGET, &result, pObject, method, 0);
QString name=QString::fromWCharArray(result.bstrVal);
But I can't seem to find a property to get the type of object (textbox, commandbutton and etc). In VBA, there is a TypeName() function to get the type. So how can I actually do it in OLE automation autowrap function? Thanks.
Here is an example... could be optimized with a function to check the result and throw/catch an exception, but it is what it is.
#include <windows.h>
#include <atlbase.h>
#include <comdef.h>
#include <stdio.h>
int main(int argc, TCHAR* argv[])
{
class CComInit
{
public:
CComInit()
{
CoInitialize(NULL);
}
~CComInit()
{
CoUninitialize();
}
} _init;
IDispatchPtr lpDisp;
HRESULT hr = lpDisp.CreateInstance(L"Scripting.FileSystemObject");
if (FAILED(hr))
{
_com_error err(hr);
printf("Error %s\n", err.ErrorMessage());
return 0;
}
ITypeInfoPtr lpTypeInfo;
hr = lpDisp->GetTypeInfo(0, 0, &lpTypeInfo);
if (FAILED(hr))
{
_com_error err(hr);
printf("Error %s\n", err.ErrorMessage());
return 0;
}
CComBSTR ccbName, ccbDocString;
hr = lpTypeInfo->GetDocumentation(-1, &ccbName, &ccbDocString, NULL, NULL) ;
if (FAILED(hr))
{
_com_error err(hr);
printf("Error %s\n", err.ErrorMessage());
return 0;
}
printf("Type name: %S\n", ccbName.m_str);
printf("Doc: %S\n", ccbDocString.m_str);
return 0;
}
I’m looking for a class like QSprite, which takes responsibility for reading pixmaps from a source file, split the source image into sequence of images and return sub image by index.
Something like this:
class QSprite2
{
bool load(QUrl url, QSize frameSize);
QImage getFrame(int index);
};
Is there any way to get described functionality with existing classes. Or maybe I have to implement the describe logic by myself?
You can use QQuickImageProvider. Here's a class I wrote that does something similar:
SpriteImageProvider.h:
#ifndef SPRITEIMAGEPROVIDER_H
#define SPRITEIMAGEPROVIDER_H
#include <QHash>
#include <QImage>
#include <QString>
#include <QQuickImageProvider>
#include "IsleGlobal.h"
class ISLE_EXPORT SpriteImageProvider : public QQuickImageProvider
{
public:
SpriteImageProvider();
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
private:
int parseFrameIndex(const QString &frameIndexStr) const;
int parseFrameWidth(const QString &frameWidthStr) const;
int parseFrameHeight(const QString &frameHeightStr) const;
QHash<QString, QImage> mImages;
};
#endif // SPRITEIMAGEPROVIDER_H
SpriteImageProvider.cpp:
#include "SpriteImageProvider.h"
#include <QImage>
#include <QDebug>
SpriteImageProvider::SpriteImageProvider() :
QQuickImageProvider(QQmlImageProviderBase::Image)
{
}
static const QRgb whiteRgba = qRgba(255, 255, 255, 255);
static const QRgb magentaRgba = qRgba(255, 0, 255, 255);
static const QRgb transparentRgba = qRgba(0, 0, 0, 0);
QImage SpriteImageProvider::requestImage(const QString &id, QSize *size, const QSize &)
{
QStringList args = id.split(QLatin1String(","));
if (args.length() < 1) {
qWarning() << "Must pass at least the file name as arguments for SpriteImageProvider source";
return QImage();
} else if (args.length() != 1 && args.length() != 2 && args.length() != 4) {
qWarning() << "Must pass either (fileName), (fileName, frameIndex) or"
<< "(fileName, frameWidth, frameHeight, frameIndex) as arguments for SpriteImageProvider source";
return QImage();
}
const QString imageFilename = ":/" + args.first();
int frameIndex = -2;
int frameWidth = -2;
int frameHeight = -2;
if (args.length() > 1) {
frameIndex = parseFrameIndex(args.last());
if (frameIndex == -1)
return QImage();
}
if (args.length() == 4) {
frameWidth = parseFrameIndex(args.at(1));
if (frameWidth == -1)
return QImage();
frameHeight = parseFrameIndex(args.at(2));
if (frameHeight == -1)
return QImage();
}
QHash<QString, QImage>::const_iterator it = mImages.find(imageFilename);
if (it == mImages.end()) {
QImage image(imageFilename);
if (image.isNull()) {
qWarning() << "Failed to load image at" << imageFilename;
return image;
}
// TODO: is there a better way of doing this?
QImage alphaImage = image;
for (int y = 0; y < alphaImage.height(); ++y) {
for (int x = 0; x < alphaImage.width(); ++x) {
const QRgb pixelRgb = alphaImage.pixel(x, y);
if (pixelRgb == whiteRgba || pixelRgb == magentaRgba)
alphaImage.setPixel(x, y, transparentRgba);
}
}
mImages.insert(imageFilename, alphaImage);
it = mImages.find(imageFilename);
}
if (frameWidth == -2 || frameHeight == -2) {
if (frameIndex == -2) {
// Use the whole image.
frameWidth = it.value().width();
frameHeight = it.value().height();
frameIndex = 0;
} else {
frameWidth = 64;
frameHeight = 64;
}
}
// Copy an individual frame out of the larger image.
const int framesWide = it.value().width() / frameWidth;
const QRect subRect((frameIndex % framesWide) * frameWidth,
(frameIndex / framesWide) * frameHeight,
frameWidth,
frameHeight);
// qDebug() << "id" << id;
// qDebug() << "framesWide" << framesWide;
// qDebug() << "subRect" << subRect;
const QImage frameImage = it.value().copy(subRect);
*size = frameImage.size();
return frameImage;
}
int SpriteImageProvider::parseFrameIndex(const QString &frameIndexStr) const
{
bool convertedToIntSuccessfully = false;
const int frameIndex = frameIndexStr.toInt(&convertedToIntSuccessfully);
if (!convertedToIntSuccessfully) {
qWarning() << "Failed to convert frame index" << frameIndexStr << "to an int";
return -1;
}
return frameIndex;
}
int SpriteImageProvider::parseFrameWidth(const QString &frameWidthStr) const
{
bool convertedToIntSuccessfully = false;
const int frameWidth = frameWidthStr.toInt(&convertedToIntSuccessfully);
if (!convertedToIntSuccessfully) {
qWarning() << "Failed to convert frame width" << frameWidthStr << "to an int";
return -1;
}
return frameWidth;
}
int SpriteImageProvider::parseFrameHeight(const QString &frameHeightStr) const
{
bool convertedToIntSuccessfully = false;
const int frameHeight = frameHeightStr.toInt(&convertedToIntSuccessfully);
if (!convertedToIntSuccessfully) {
qWarning() << "Failed to convert frame height" << frameHeightStr << "to an int";
return -1;
}
return frameHeight;
}
It also supports "alpha keys" - white and magenta pixels in the source image will be turned into transparent pixels.
It's registered with the QML engine like this:
mEngine->addImageProvider("sprite", new SpriteImageProvider);
and used in QML like this:
import QtQuick 2.5
Image {
source: qsTr('image://sprite/sprites/hugh.png,%1').arg(_sceneItemComponent ? _sceneItemComponent.facingDirection : 0)
}
where facingDirection is the frame index to use. There are also other arguments you can pass that are mentioned in the .cpp file.
I am trying to use the example code from here.
I have made some changes in order to save the images to the computer. When I read the data in MATLAB it seems like values that should be 0 are set to 2047, and overall it does not seem to be correct when I reconstruct the 3D points using the default intrinsic camera parameters.
What I want to achieve is to save the images so that I can use
img = single(imread(depth.png'))/ 1000
and have the depth values in meters, and pixels with no measurements should be zero.
It is the Kinect V1 by the way.
Here is the code with comments where I have tried to change.
#include "libfreenect.hpp"
#include <iostream>
#include <vector>
#include <cmath>
#include <pthread.h>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
using namespace cv;
using namespace std;
class myMutex {
public:
myMutex() {
pthread_mutex_init( &m_mutex, NULL );
}
void lock() {
pthread_mutex_lock( &m_mutex );
}
void unlock() {
pthread_mutex_unlock( &m_mutex );
}
private:
pthread_mutex_t m_mutex;
};
// Should one use FREENECT_DEPTH_REGISTERED instead of FREENECT_DEPTH_11BIT?
class MyFreenectDevice : public Freenect::FreenectDevice {
public:
MyFreenectDevice(freenect_context *_ctx, int _index)
: Freenect::FreenectDevice(_ctx, _index), m_buffer_depth(FREENECT_DEPTH_11BIT),
m_buffer_rgb(FREENECT_VIDEO_RGB), m_gamma(2048), m_new_rgb_frame(false),
m_new_depth_frame(false), depthMat(Size(640,480),CV_16UC1),
rgbMat(Size(640,480), CV_8UC3, Scalar(0)),
ownMat(Size(640,480),CV_8UC3,Scalar(0)) {
for( unsigned int i = 0 ; i < 2048 ; i++) {
float v = i/2048.0;
v = std::pow(v, 3)* 6;
m_gamma[i] = v*6*256;
}
}
// Do not call directly even in child
void VideoCallback(void* _rgb, uint32_t timestamp) {
std::cout << "RGB callback" << std::endl;
m_rgb_mutex.lock();
uint8_t* rgb = static_cast<uint8_t*>(_rgb);
rgbMat.data = rgb;
m_new_rgb_frame = true;
m_rgb_mutex.unlock();
};
// Do not call directly even in child
void DepthCallback(void* _depth, uint32_t timestamp) {
std::cout << "Depth callback" << std::endl;
m_depth_mutex.lock();
uint16_t* depth = static_cast<uint16_t*>(_depth);
// Here I use memcpy instead so I can use uint16
// memcpy(depthMat.data,depth,depthMat.rows*depthMat.cols*sizeof(uint16_t));
depthMat.data = (uchar*) depth;
m_new_depth_frame = true;
m_depth_mutex.unlock();
}
bool getVideo(Mat& output) {
m_rgb_mutex.lock();
if(m_new_rgb_frame) {
cv::cvtColor(rgbMat, output, CV_RGB2BGR);
m_new_rgb_frame = false;
m_rgb_mutex.unlock();
return true;
} else {
m_rgb_mutex.unlock();
return false;
}
}
bool getDepth(Mat& output) {
m_depth_mutex.lock();
if(m_new_depth_frame) {
depthMat.copyTo(output);
m_new_depth_frame = false;
m_depth_mutex.unlock();
return true;
} else {
m_depth_mutex.unlock();
return false;
}
}
private:
// Should it be uint16_t instead or even higher?
std::vector<uint8_t> m_buffer_depth;
std::vector<uint8_t> m_buffer_rgb;
std::vector<uint16_t> m_gamma;
Mat depthMat;
Mat rgbMat;
Mat ownMat;
myMutex m_rgb_mutex;
myMutex m_depth_mutex;
bool m_new_rgb_frame;
bool m_new_depth_frame;
};
int main(int argc, char **argv) {
bool die(false);
string filename("snapshot");
string suffix(".png");
int i_snap(0),iter(0);
Mat depthMat(Size(640,480),CV_16UC1);
Mat depthf (Size(640,480),CV_8UC1);
Mat rgbMat(Size(640,480),CV_8UC3,Scalar(0));
Mat ownMat(Size(640,480),CV_8UC3,Scalar(0));
// The next two lines must be changed as Freenect::Freenect
// isn't a template but the method createDevice:
// Freenect::Freenect<MyFreenectDevice> freenect;
// MyFreenectDevice& device = freenect.createDevice(0);
// by these two lines:
Freenect::Freenect freenect;
MyFreenectDevice& device = freenect.createDevice<MyFreenectDevice>(0);
namedWindow("rgb",CV_WINDOW_AUTOSIZE);
namedWindow("depth",CV_WINDOW_AUTOSIZE);
device.startVideo();
device.startDepth();
while (!die) {
device.getVideo(rgbMat);
device.getDepth(depthMat);
// Here I save the depth images
std::ostringstream file;
file << filename << i_snap << suffix;
cv::imwrite(file.str(),depthMat);
cv::imshow("rgb", rgbMat);
depthMat.convertTo(depthf, CV_8UC1, 255.0/2048.0);
cv::imshow("depth",depthf);
if(iter >= 1000) break;
iter++;
}
device.stopVideo();
device.stopDepth();
return 0;
}
Thanks in advance!
Erik
I dont have any experience with OpenKinect in particular; but should your depth buffer be uint16?
std::vector<uint8_t> m_buffer_depth;
Also; for Matlab, do check if the image that you are reading is a uint16 or uint8. If its the latter then convert it to uint16
uint16(imread('depth.png'));
Sorry couldn't help more. Hope this helps.
The values you have are the raw depth values. You need to remap those into MM for the numbers to make sense. Kinect 1 can see up to 10 meters. So I would go with raw_values/2407*10000.
If the values are saturated at 2047, you are probably using the FREENECT_DEPTH_11BIT_PACKED depth format.
For work in Matlab, it is always easier to use FREENECT_DEPTH_MM or FREENECT_DEPTH_REGISTERED.
Enjoy.
This is what I have so far and I want to save pcd file from it
I know I have to do something like this but not exactly sure
pcl::PointCloud::PointPointXYZRGBA> cloud;
pcl::io:;savePCDFileASCII("test.pcd",cloud);
what do i have to add in my current code that i will have test.pcd
Thanks
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/common/time.h>
class SimpleOpenNIProcessor
{
public:
SimpleOpenNIProcessor () : viewer ("PCL OpenNI Viewer") {}
void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr &cloud)
{
static unsigned count = 0;
static double last = pcl::getTime ();
if (++count == 30)
{
double now = pcl::getTime ();
std::cout << "distance of center pixel :" << cloud->points [(cloud->width >> 1) * (cloud->height + 1)].z << " mm. Average framerate: " << double(count)/double(now - last) << " Hz" << std::endl;
count = 0;
last = now;
}
if (!viewer.wasStopped())
viewer.showCloud (cloud);
}
void run ()
{
// create a new grabber for OpenNI devices
pcl::Grabber* interface = new pcl::OpenNIGrabber();
// make callback function from member function
boost::function<void (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f =
boost::bind (&SimpleOpenNIProcessor::cloud_cb_, this, _1);
// connect callback function for desired signal. In this case its a point cloud with color values
boost::signals2::connection c = interface->registerCallback (f);
// start receiving point clouds
interface->start ();
// wait until user quits program with Ctrl-C, but no busy-waiting -> sleep (1);
while (true)
boost::this_thread::sleep (boost::posix_time::seconds (1));
// stop the grabber
interface->stop ();
}
pcl::visualization::CloudViewer viewer;
};
int main ()
{
SimpleOpenNIProcessor v;
v.run ();
return (0);
}
#include <iostream>
#include <string>
#include <sstream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
using namespace std;
const string OUT_DIR = "D:\\frame_saver_output\\";
class SimpleOpenNIViewer
{
public:
SimpleOpenNIViewer () : viewer ("PCL Viewer")
{
frames_saved = 0;
save_one = false;
}
void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &cloud)
{
if (!viewer.wasStopped()) {
viewer.showCloud (cloud);
if( save_one ) {
save_one = false;
std::stringstream out;
out << frames_saved;
std::string name = OUT_DIR + "cloud" + out.str() + ".pcd";
pcl::io::savePCDFileASCII( name, *cloud );
}
}
}
void run ()
{
pcl::Grabber* interface = new pcl::OpenNIGrabber();
boost::function<void (const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr&)> f =
boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);
interface->registerCallback (f);
interface->start ();
char c;
while (!viewer.wasStopped())
{
//sleep (1);
c = getchar();
if( c == 's' ) {
cout << "Saving frame " << frames_saved << ".\n";
frames_saved++;
save_one = true;
}
}
interface->stop ();
}
pcl::visualization::CloudViewer viewer;
private:
int frames_saved;
bool save_one;
};
int main ()
{
SimpleOpenNIViewer v;
v.run ();
return 0;
}
Here you go.