I'm new about opencv(c++) and kinect. I try to take a video image with c++ from kinect. I search everywhere but I didn't find anything. Because people are made using openNI or OpenKinect. I don't want to use this lib. How can I do it??
Thanks!!!
You could use the kinect for windows SDK to grab the frames, and then convert them to an opencv format. See this code example which does that in visual studio (found in this thread on the microsoft forums), unfortunately I don't have a kinect right now to test the code:
#include "stdafx.h"
#define COLOR_WIDTH 640
#define COLOR_HIGHT 480
#define DEPTH_WIDTH 320
#define DEPTH_HIGHT 240
#define SKELETON_WIDTH 640
#define SKELETON_HIGHT 480
#define CHANNEL 3
BYTE buf[DEPTH_WIDTH * DEPTH_HIGHT * CHANNEL];
int drawColor(HANDLE h, IplImage* color)
{
const NUI_IMAGE_FRAME * pImageFrame = NULL;
HRESULT hr = NuiImageStreamGetNextFrame(h, 0, &pImageFrame);
if (FAILED(hr))
{
cout << "Get Image Frame Failed" << endl;
return -1;
}
NuiImageBuffer * pTexture = pImageFrame->pFrameTexture;
KINECT_LOCKED_RECT LockedRect;
pTexture->LockRect(0, &LockedRect, NULL, 0);
if (LockedRect.Pitch != 0)
{
BYTE * pBuffer = (BYTE*) LockedRect.pBits;
cvSetData(color, pBuffer, LockedRect.Pitch);
}
cvShowImage("color image", color);
NuiImageStreamReleaseFrame(h, pImageFrame);
return 0;
}
int drawDepth(HANDLE h, IplImage* depth)
{
const NUI_IMAGE_FRAME * pImageFrame = NULL;
HRESULT hr = NuiImageStreamGetNextFrame(h, 0, &pImageFrame);
if (FAILED(hr))
{
cout << "Get Image Frame Failed" << endl;
return -1;
}
// temp1 = depth;
NuiImageBuffer * pTexture = pImageFrame->pFrameTexture;
KINECT_LOCKED_RECT LockedRect;
pTexture->LockRect(0, &LockedRect, NULL, 0);
if (LockedRect.Pitch != 0)
{
USHORT * pBuff = (USHORT*) LockedRect.pBits;
for (int i = 0; i < DEPTH_WIDTH * DEPTH_HIGHT; i++)
{
BYTE index = pBuff[i] & 0x07;
USHORT realDepth = (pBuff[i] & 0xFFF8) >> 3;
BYTE scale = 255 - (BYTE)(256 * realDepth / 0x0fff);
buf[CHANNEL * i] = buf[CHANNEL * i + 1] = buf[CHANNEL * i + 2] = 0;
switch (index)
{
case 0:
buf[CHANNEL * i] = scale / 2;
buf[CHANNEL * i + 1] = scale / 2;
buf[CHANNEL * i + 2] = scale / 2;
break;
case 1:
buf[CHANNEL * i] = scale;
break;
case 2:
buf[CHANNEL * i + 1] = scale;
break;
case 3:
buf[CHANNEL * i + 2] = scale;
break;
case 4:
buf[CHANNEL * i] = scale;
buf[CHANNEL * i + 1] = scale;
break;
case 5:
buf[CHANNEL * i] = scale;
buf[CHANNEL * i + 2] = scale;
break;
case 6:
buf[CHANNEL * i + 1] = scale;
buf[CHANNEL * i + 2] = scale;
break;
case 7:
buf[CHANNEL * i] = 255 - scale / 2;
buf[CHANNEL * i + 1] = 255 - scale / 2;
buf[CHANNEL * i + 2] = 255 - scale / 2;
break;
}
}
cvSetData(depth, buf, DEPTH_WIDTH * CHANNEL);
}
NuiImageStreamReleaseFrame(h, pImageFrame);
cvShowImage("depth image", depth);
return 0;
}
int drawSkeleton(IplImage* skeleton)
{
NUI_SKELETON_FRAME SkeletonFrame;
CvPoint pt[20];
HRESULT hr = NuiSkeletonGetNextFrame(0, &SkeletonFrame);
bool bFoundSkeleton = false;
for (int i = 0; i < NUI_SKELETON_COUNT; i++)
{
if (SkeletonFrame.SkeletonData[i].eTrackingState
== NUI_SKELETON_TRACKED)
{
bFoundSkeleton = true;
}
}
// Has skeletons!
//
if (bFoundSkeleton)
{
NuiTransformSmooth(&SkeletonFrame, NULL);
memset(skeleton->imageData, 0, skeleton->imageSize);
for (int i = 0; i < NUI_SKELETON_COUNT; i++)
{
if (SkeletonFrame.SkeletonData[i].eTrackingState
== NUI_SKELETON_TRACKED)
{
for (int j = 0; j < NUI_SKELETON_POSITION_COUNT; j++)
{
float fx, fy;
NuiTransformSkeletonToDepthImageF(
SkeletonFrame.SkeletonData[i].SkeletonPositions[j],
&fx, &fy);
pt[j].x = (int) (fx * SKELETON_WIDTH + 0.5f);
pt[j].y = (int) (fy * SKELETON_HIGHT + 0.5f);
cvCircle(skeleton, pt[j], 5, CV_RGB(255, 0, 0), -1);
}
cvLine(skeleton, pt[NUI_SKELETON_POSITION_HEAD],
pt[NUI_SKELETON_POSITION_SHOULDER_CENTER],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_SHOULDER_CENTER],
pt[NUI_SKELETON_POSITION_SPINE], CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_SPINE],
pt[NUI_SKELETON_POSITION_HIP_CENTER],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_HAND_RIGHT],
pt[NUI_SKELETON_POSITION_WRIST_RIGHT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_WRIST_RIGHT],
pt[NUI_SKELETON_POSITION_ELBOW_RIGHT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_ELBOW_RIGHT],
pt[NUI_SKELETON_POSITION_SHOULDER_RIGHT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_SHOULDER_RIGHT],
pt[NUI_SKELETON_POSITION_SHOULDER_CENTER],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_SHOULDER_CENTER],
pt[NUI_SKELETON_POSITION_SHOULDER_LEFT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_SHOULDER_LEFT],
pt[NUI_SKELETON_POSITION_ELBOW_LEFT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_ELBOW_LEFT],
pt[NUI_SKELETON_POSITION_WRIST_LEFT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_WRIST_LEFT],
pt[NUI_SKELETON_POSITION_HAND_LEFT], CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_HIP_CENTER],
pt[NUI_SKELETON_POSITION_HIP_RIGHT], CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_HIP_RIGHT],
pt[NUI_SKELETON_POSITION_KNEE_RIGHT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_KNEE_RIGHT],
pt[NUI_SKELETON_POSITION_ANKLE_RIGHT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_ANKLE_RIGHT],
pt[NUI_SKELETON_POSITION_FOOT_RIGHT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_HIP_CENTER],
pt[NUI_SKELETON_POSITION_HIP_LEFT], CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_HIP_LEFT],
pt[NUI_SKELETON_POSITION_KNEE_LEFT], CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_KNEE_LEFT],
pt[NUI_SKELETON_POSITION_ANKLE_LEFT],
CV_RGB(0, 255, 0));
cvLine(skeleton, pt[NUI_SKELETON_POSITION_ANKLE_LEFT],
pt[NUI_SKELETON_POSITION_FOOT_LEFT], CV_RGB(0, 255, 0));
}
}
}
cvShowImage("skeleton image", skeleton);
return 0;
}
int main(int argc, char * argv[])
{
IplImage* color = cvCreateImageHeader(cvSize(COLOR_WIDTH, COLOR_HIGHT), IPL_DEPTH_8U, 4);
IplImage* depth = cvCreateImageHeader(cvSize(DEPTH_WIDTH, DEPTH_HIGHT),IPL_DEPTH_8U, CHANNEL);
IplImage* skeleton = cvCreateImage(cvSize(SKELETON_WIDTH, SKELETON_HIGHT),IPL_DEPTH_8U, CHANNEL);
cvNamedWindow("color image", CV_WINDOW_AUTOSIZE);
cvNamedWindow("depth image", CV_WINDOW_AUTOSIZE);
cvNamedWindow("skeleton image", CV_WINDOW_AUTOSIZE);
HRESULT hr = NuiInitialize(
NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX
| NUI_INITIALIZE_FLAG_USES_COLOR
| NUI_INITIALIZE_FLAG_USES_SKELETON);
if (hr != S_OK)
{
cout << "NuiInitialize failed" << endl;
return hr;
}
HANDLE h1 = CreateEvent(NULL, TRUE, FALSE, NULL);
HANDLE h2 = NULL;
hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480,
0, 2, h1, &h2);
if (FAILED(hr))
{
cout << "Could not open image stream video" << endl;
return hr;
}
HANDLE h3 = CreateEvent(NULL, TRUE, FALSE, NULL);
HANDLE h4 = NULL;
hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX,
NUI_IMAGE_RESOLUTION_320x240, 0, 2, h3, &h4);
if (FAILED(hr))
{
cout << "Could not open depth stream video" << endl;
return hr;
}
HANDLE h5 = CreateEvent(NULL, TRUE, FALSE, NULL);
hr = NuiSkeletonTrackingEnable(h5, 0);
if (FAILED(hr))
{
cout << "Could not open skeleton stream video" << endl;
return hr;
}
while (1)
{
WaitForSingleObject(h1, INFINITE);
drawColor(h2, color);
WaitForSingleObject(h3, INFINITE);
drawDepth(h4, depth);
WaitForSingleObject(h5, INFINITE);
drawSkeleton(skeleton);
//exit
int c = cvWaitKey(1);
if (c == 27 || c == 'q' || c == 'Q')
break;
}
cvReleaseImageHeader(&depth);
cvReleaseImageHeader(&color);
cvReleaseImage(&skeleton);
cvDestroyWindow("depth image");
cvDestroyWindow("color image");
cvDestroyWindow("skeleton image");
NuiShutdown();
return 0;
}
OpenCV does not offer the ability to connect to and process data from the Kinect sensor; unless you treat the Kinect as a regular webcam. You will want to fetch the data using one of the APIs and send it to OpenCV. To get the data from the Kinect you can use:
Microsoft Kinect for Windows SDK
OpenKinect's libfreenect API
OpenNI + OpenKinect
If your employer has a problem with one of the APIs, that is there choice. But the use of OpenCV does not eliminate your need to use one of them.
A quick search on MSDN reveals multiple threads on the the subject. The most straight forward approach I've read about is using cvSetData to import the data, after converting the image:
RGB
IplImage * ovImage = NULL;
ovImage = cvCreateImage(cvSize(640, 480), 8, 4);
cvSetData(ovImage, pBuffer, ovImage->widthStep);
Depth
ovImage = cvCreateImage(cvSize(640, 480), 8, 1);
I also found the freenomad_vision project on GitHub that provides libfreenect support with OpenCV and OpenGL. If you dislike using libfreenect, the code can easily serve as reference since the incoming data is all the same and (likely) would be converted the same.
In case if someone is redirected here looking for a simpler method for visualizing the Kinect depth stream, I was able to do this in the following way
for the KinectV2.
Mat CDepthMap::getFrame()
{
IDepthFrame* frame;
Mat depthImage;
hr = _depth_reader->AcquireLatestFrame(&frame);
if (SUCCEEDED(hr)) {
const UINT imgSize = sDepthWidth*sDepthHeight; //512*424
UINT16 pixelData[imgSize];
hr = frame->CopyFrameDataToArray(imgSize, pixelData);
if (SUCCEEDED(hr)) {
depthImage = Mat(sDepthHeight,sDepthWidth, CV_8U);
for (UINT i = 0; i < imgSize; i++) {
UINT16 depth = pixelData[i];
depthImage.at<UINT8>(i) = LOWORD(depth);
}
}
SafeRelease(frame);
}
return depthImage;
}
Related
I am running an infinite loop and every frame I'm taking a screenshot from a desired window and turning it into a Mat then searching that Mat for a template image using matchTemplate. If I read in the template image and the entire image, I can use the function successfully using the TM_SQDIFF method. However, when I run the below code, a rectangle is always drawn even if the template isn't there and is never over the template if the template is present. Any ideas?
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include "opencv2/imgproc.hpp"
#include <Windows.h>
#include <iostream>
using namespace std;
using namespace cv;
Mat getMat(HWND hWND);
int main()
{
//Window capture
LPCWSTR windowTitle = L"imgName - Paint";
HWND hWND = FindWindow(NULL, windowTitle);
while (!hWND)
{
system("cls");
cout << "Start game" << endl;
hWND = FindWindow(NULL, windowTitle);
Sleep(100);
}
enum TemplateMatchModes
{
TM_SQDIFF = 0,
TM_SQDIFF_NORMED = 1,
TM_CCORR = 2,
TM_CCORR_NORMED = 3,
TM_CCOEFF = 4,
TM_CCOEFF_NORMED = 5
};
TemplateMatchModes option = TM_SQDIFF;
Mat templateImage = imread("images/templateImg.jpg", IMREAD_COLOR);
Mat otherThing;
templateImage.convertTo(otherThing, CV_8UC4);
namedWindow("Result", WINDOW_NORMAL);
while (true)
{
double minVal;
double maxVal;
Point minLoc;
Point maxLoc;
Point matchLoc;
Mat theImage = getMat(hWND);
Mat result;
Mat background;
theImage.copyTo(background);
cvtColor(theImage, theImage, COLOR_BGR2HSV);
matchTemplate(theImage, otherThing, result, option);
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
if (option == TM_SQDIFF || option == TM_SQDIFF_NORMED)
{
matchLoc = minLoc;
}
else
{
matchLoc = maxLoc;
}
rectangle(background, matchLoc, Point(matchLoc.x + otherThing.cols, matchLoc.y + otherThing.rows), Scalar(0, 255, 0), 2, 8, 0);
imshow("Result", background);
waitKey(30);
}
}
Mat getMat(HWND hWND)
{
HDC deviceContext = GetDC(hWND);
HDC memoryDeviceContext = CreateCompatibleDC(deviceContext);
RECT windowRect;
GetClientRect(hWND, &windowRect);
int height = windowRect.bottom;
int width = windowRect.right;
HBITMAP bitmap = CreateCompatibleBitmap(deviceContext, width, height);
SelectObject(memoryDeviceContext, bitmap);
BitBlt(memoryDeviceContext, 0, 0, width, height, deviceContext, 0, 0, SRCCOPY);
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width;
bi.biHeight = -height;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 1;
bi.biYPelsPerMeter = 1;
bi.biClrUsed = 1;
bi.biClrImportant = 1;
Mat mat = Mat(height, width, CV_8UC4);
GetDIBits(memoryDeviceContext, bitmap, 0, height, mat.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
DeleteObject(bitmap);
DeleteDC(memoryDeviceContext);
ReleaseDC(hWND, deviceContext);
return mat;
}
There is no condition given for rectangle to not to be drawn. If you want it to be drawn only if the template found you should create a condition for that.
You may check some detection examples as well.
How to make my video not delay, in the beginning of the code it's not delay, but if I use the GaussianBlur, morphology operation, and SimpleBlobDetector, the video gets delayed, please someone help me..
Thanks in advance
using namespace cv;
using namespace std;
int _tmain(int argc, _TCHAR* argv[]){
VideoCapture cap(0);
cap.open("file.mp4"); //read the video
if (!cap.isOpened())
{
cout << "Cannot open the video cam" << endl;
return -1;
}
double Width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double Height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cvNamedWindow("MyVideo", CV_WINDOW_AUTOSIZE);
while (1)
{
Mat frame;
bool bSuccess = cap.read(frame);
SimpleBlobDetector::Params params;
// Change thresholds
params.minThreshold = 0;
params.maxThreshold = 255;
params.filterByColor = true;
params.blobColor = 255;
// Filter by Area.
params.filterByArea = true;
params.minArea = 5 ;
// Filter by Circularity
params.filterByCircularity = true;
params.minCircularity = 0.1;
// Filter by Convexity
params.filterByConvexity = true;
params.minConvexity = 0.87;
// Filter by Inertia
params.filterByInertia = true;
params.minInertiaRatio = 0.01;
//crop the image with the pixel i want
Mat blur, crop;
GaussianBlur(frame, blur, Size(15, 15), 0); //blur the image
Point corners[1][4];
corners[0][0] = Point(550, 30); //top left
corners[0][1] = Point(250, 700); //bottom left
corners[0][2] = Point(1100, 700); //bottom right
corners[0][3] = Point(600, 30); //top right
const Point* corner_list[1] = { corners[0] };
int num_points = 4;
int num_polygons = 1;
int line_type = 8;
Mat mask(720, 1280, CV_8UC3, cv::Scalar(0, 0, 0));
fillPoly(mask, corner_list, &num_points, num_polygons, cv::Scalar(255, 255, 255), line_type);
bitwise_and(blur, mask, crop);//combine the image
Mat gray, changeToBlack;
cvtColor(crop, gray, COLOR_BGR2GRAY); //grayscale citra
inRange(gray, Scalar(0), Scalar(0), changeToBlack);
Mat black_image(gray.size(), CV_8U, Scalar(255));
black_image.copyTo(gray, changeToBlack);
Mat thres, tes;
threshold(gray, tes, 51, 255, THRESH_BINARY_INV); //threshold citra and 51 set value
Mat erosi, dilasi, open, close, tophat;
Mat kernel = Mat(3, 3, CV_8UC1, Scalar(1));
morphologyEx(tes, erosi, MORPH_ERODE, kernel, Point(-1, -1), 3);
morphologyEx(erosi, dilasi, MORPH_DILATE, kernel, Point(-1, -1), 20);
vector<KeyPoint> keypoints;
Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);
detector->detect(dilasi, keypoints);
Mat im_with_keypoints;
drawKeypoints(dilasi, keypoints, im_with_keypoints, Scalar(205, 0, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
imshow("gray", frame);
imshow("MyVideo", im_with_keypoints);
if (waitKey(30) == 27)
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
Anyone please help me
Oh! All actions and memory allocation inside loop. Try this:
int _tmain(int argc, _TCHAR* argv[]){
VideoCapture cap(0);
cap.open("file.mp4"); //read the video
if (!cap.isOpened())
{
cout << "Cannot open the video cam" << endl;
return -1;
}
double Width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double Height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cvNamedWindow("MyVideo", CV_WINDOW_AUTOSIZE);
Mat frame;
Mat blur, crop;
Mat mask(720, 1280, CV_8UC3, cv::Scalar(0, 0, 0));
Mat gray, changeToBlack;
Mat black_image(gray.size(), CV_8U, Scalar(255));
Mat thres, tes;
Mat erosi, dilasi, open, close, tophat;
Mat kernel = Mat(3, 3, CV_8UC1, Scalar(1));
Mat im_with_keypoints;
SimpleBlobDetector::Params params;
// Change thresholds
params.minThreshold = 0;
params.maxThreshold = 255;
params.filterByColor = true;
params.blobColor = 255;
// Filter by Area.
params.filterByArea = true;
params.minArea = 5 ;
// Filter by Circularity
params.filterByCircularity = true;
params.minCircularity = 0.1;
// Filter by Convexity
params.filterByConvexity = true;
params.minConvexity = 0.87;
// Filter by Inertia
params.filterByInertia = true;
params.minInertiaRatio = 0.01;
vector<KeyPoint> keypoints;
Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);
while (cap.read(frame))
{
//crop the image with the pixel i want
GaussianBlur(frame, blur, Size(15, 15), 0); //blur the image
Point corners[1][4];
corners[0][0] = Point(550, 30); //top left
corners[0][1] = Point(250, 700); //bottom left
corners[0][2] = Point(1100, 700); //bottom right
corners[0][3] = Point(600, 30); //top right
const Point* corner_list[1] = { corners[0] };
int num_points = 4;
int num_polygons = 1;
int line_type = 8;
fillPoly(mask, corner_list, &num_points, num_polygons, cv::Scalar(255, 255, 255), line_type);
bitwise_and(blur, mask, crop);//combine the image
cvtColor(crop, gray, COLOR_BGR2GRAY); //grayscale citra
inRange(gray, Scalar(0), Scalar(0), changeToBlack);
black_image.copyTo(gray, changeToBlack);
threshold(gray, tes, 51, 255, THRESH_BINARY_INV); //threshold citra and 51 set value
morphologyEx(tes, erosi, MORPH_ERODE, kernel, Point(-1, -1), 3);
morphologyEx(erosi, dilasi, MORPH_DILATE, kernel, Point(-1, -1), 20);
detector->detect(dilasi, keypoints);
drawKeypoints(dilasi, keypoints, im_with_keypoints, Scalar(205, 0, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
imshow("gray", frame);
imshow("MyVideo", im_with_keypoints);
if (waitKey(1) == 27)
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
How can I convert efficiently from a cv::Mat to a vtkImageData in C++?
I search for a method that works for BW and COLOR images.
Below is a simplified version of the answer above by #lucasahli. It uses an efficient memcpy instead of a double for loop.
NOTE: For color images, you may need to flip the image channels from bgr to rgb ordering, which i used mixChannels to achieve.
vtkSmartPointer<vtkImageData> OpenCVToVtkConverter::convertCVMatToVtkImageData(const cv::Mat &sourceCVImage, bool flipOverXAxis) {
vtkSmartPointer<vtkImageData> outputVtkImage = vtkSmartPointer<vtkImageData>::New();
int numOfChannels = sourceCVImage.channels();
// dimension set to 1 for z since it's 2D
outputVtkImage->SetDimensions(sourceCVImage.cols, sourceCVImage.rows, 1);
// NOTE: if your image isn't uchar for some reason you'll need to change this type
outputVtkImage->AllocateScalars(VTK_UNSIGNED_CHAR, numOfChannels);
// the flipped image data gets put into tempCVImage
cv::Mat tempCVImage;
if(flipOverXAxis){ // Normally you should flip the image!
cv::flip(sourceCVImage, tempCVImage, 0);
}
else {
tempCVImage = sourceCVImage;
}
// the number of byes in the cv::Mat, assuming the data type is uchar
size_t byte_count = sourceCVImage.cols * sourceCVImage.rows * numOfChannels * sizeof(unsigned char);
// copy the internal cv::Mat data into the vtkImageData pointer
memcpy(outputVtkImage->GetScalarPointer(), tempCVImage.data, byte_count);
outputVtkImage->Modified();
return outputVtkImage;
}
vtkSmartPointer<vtkImageData> OpenCVToVtkConverter::convertCVMatToVtkImageData(const cv::Mat &sourceCVImage, bool flipOverXAxis) {
vtkSmartPointer<vtkImageData> outputVtkImage = vtkSmartPointer<vtkImageData>::New();
double spacing[3] = {1, 1, 1};
double origin[3] = {0, 0, 0};
int extent[6] = {0, sourceCVImage.cols - 1, 0, sourceCVImage.rows - 1, 0, 0};
auto numOfChannels = sourceCVImage.channels();
outputVtkImage->SetSpacing(spacing);
outputVtkImage->SetOrigin(origin);
outputVtkImage->SetExtent(extent);
outputVtkImage->SetDimensions(sourceCVImage.cols, sourceCVImage.rows, 1);
outputVtkImage->AllocateScalars(VTK_UNSIGNED_CHAR, numOfChannels);
cv::Mat tempCVImage;
if(flipOverXAxis){ // Normaly you should flip the image!
cv::flip(sourceCVImage, tempCVImage, 0);
}
else {
tempCVImage = sourceCVImage;
}
for (int imgHeightPos = 0; imgHeightPos < sourceCVImage.rows; ++imgHeightPos) {
for (int imgWidthPos = 0; imgWidthPos < sourceCVImage.cols; ++imgWidthPos){
switch(numOfChannels){
case 1:{
auto pixel = tempCVImage.at<unsigned char>(imgHeightPos, imgWidthPos);
outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 0, pixel); //red
break;
}
case 3: {
auto pixel2 = tempCVImage.at<cv::Vec3b>(imgHeightPos, imgWidthPos);
outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 0, pixel2[2]); //red
outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 1, pixel2[1]); //green
outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 2, pixel2[0]); //blue
break;
}
case 4:{
auto pixel3 = tempCVImage.at<cv::Vec4b>(imgHeightPos, imgWidthPos);
outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 0, pixel3[2]); //red
outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 1, pixel3[1]); //green
outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 2, pixel3[0]); //blue
outputVtkImage->SetScalarComponentFromDouble(imgWidthPos, imgHeightPos, 0, 3, pixel3[3]); //alpha
break;
}
default:
std::cout << "unknown number of channels" << std::endl;
}
}
}
outputVtkImage->Modified();
return outputVtkImage;
}
Trying to convert 32,24,16,8 bit images to their grayscale presentation. I read about using BitBlt, but maybe exist some light way built-in opportunity
in GDI+?
Code:
#include <vector>
...
class gdiplus_init
{
ULONG_PTR token;
public:
gdiplus_init()
{
Gdiplus::GdiplusStartupInput tmp;
Gdiplus::GdiplusStartup(&token, &tmp, NULL);
}
~gdiplus_init()
{
Gdiplus::GdiplusShutdown(token);
}
};
bool getbits(const wchar_t *filename, Gdiplus::PixelFormat pixelformat,
std::vector<BYTE> &bitmapinfo, std::vector<BYTE> &bits, int &w, int &h)
{
gdiplus_init init;
WORD bpp = 0;
int usage = DIB_RGB_COLORS;
int palettesize = 0;
switch(pixelformat)
{
case PixelFormat8bppIndexed:
bpp = 8;
usage = DIB_PAL_COLORS;
palettesize = 256 * sizeof(RGBQUAD);
break;
case PixelFormat16bppRGB555: bpp = 16; break;
case PixelFormat16bppRGB565: bpp = 16; break;
case PixelFormat24bppRGB: bpp = 24; break;
case PixelFormat32bppRGB: bpp = 32; break;
default:return false;
}
auto src = Gdiplus::Bitmap::FromFile(filename);
if(src->GetLastStatus() != Gdiplus::Status::Ok)
return false;
auto dst = src->Clone(0, 0, src->GetWidth(), src->GetHeight(),
pixelformat);
w = src->GetWidth();
h = src->GetHeight();
HBITMAP hbitmap;
Gdiplus::Color color;
dst->GetHBITMAP(color, &hbitmap);
//allocate enough memory for bitmapinfo and initialize to zero
//it's sizeof BITMAPINFO structure + size of palette
bitmapinfo.resize(sizeof(BITMAPINFO) + palettesize, 0);
//fill the first 6 parameters
BITMAPINFO* ptr = (BITMAPINFO*)bitmapinfo.data();
ptr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); //don't skip
ptr->bmiHeader.biWidth = w;
ptr->bmiHeader.biHeight = h;
ptr->bmiHeader.biPlanes = 1;
ptr->bmiHeader.biBitCount = bpp;
ptr->bmiHeader.biCompression = BI_RGB;
//magic formula to calculate the size:
//this is roughly w * h * bytes_per_pixel, it's written this way
//to account for "bitmap padding"
DWORD size = ((w * bpp + 31) / 32) * 4 * h;
//allocate memory for image
bits.resize(size, 0);
//finally call GetDIBits to fill bits and bitmapinfo
HDC hdc = GetDC(0);
GetDIBits(hdc, hbitmap, 0, h, &bits[0], (BITMAPINFO*)&bitmapinfo[0], usage);
ReleaseDC(0, hdc);
//cleanup
delete src;
delete dst;
return true;
}
void CMFCApplicationColorsView::OnDraw(CDC* pDC)
{
...
std::vector<BYTE> bi; //automatic storage
std::vector<BYTE> bits;
int w, h;
//24-bit test
if(getbits(L"c:\\test\\24bit.bmp", PixelFormat24bppRGB, bi, bits, w, h))
StretchDIBits(dc, 0, 0, w, h, 0, 0, w, h,
bits.data(), (BITMAPINFO*)bi.data(), DIB_RGB_COLORS, SRCCOPY);
//8-bit test
if(getbits(L"c:\\test\\8bit.bmp", PixelFormat8bppIndexed, bi, bits, w, h))
StretchDIBits(dc, 0, 220, w, h, 0, 0, w, h,
bits.data(), (BITMAPINFO*)bi.data(), DIB_PAL_COLORS, SRCCOPY);
}
You can draw the GDI+ directly with various transformation. Use Gdiplus::Graphics to draw on device context.
For grayscale conversion, RGB values all have to be the same. Gdiplus::ColorMatrix can transform the colors. Green is usually more important, it gets more weight.
void draw(CDC *pdc)
{
//this line should be in OnCreate or somewhere other than paint routine
Gdiplus::Bitmap source(L"file.jpg");
//gray scale conversion:
Gdiplus::ColorMatrix matrix =
{
.3f, .3f, .3f, 0, 0,
.6f, .6f, .6f, 0, 0,
.1f, .1f, .1f, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1
};
Gdiplus::ImageAttributes attr;
attr.SetColorMatrix(&matrix,
Gdiplus::ColorMatrixFlagsDefault, Gdiplus::ColorAdjustTypeBitmap);
Gdiplus::Graphics gr(pdc->GetSafeHdc());
Gdiplus::REAL w = (Gdiplus::REAL)source.GetWidth();
Gdiplus::REAL h = (Gdiplus::REAL)source.GetHeight();
Gdiplus::RectF rect(0, 0, w, h);
gr.DrawImage(&source, rect, 0, 0, w, h, Gdiplus::UnitPixel, &attr);
}
Note, I used rough values for grayscale matrix. See the answer mentioned in comment for a better matrix.
To convert the file, the process is similar, except use Gdiplus::Graphics to create memory dc and save it.
int GetEncoderClsid(const WCHAR* format, CLSID* clsid)
{
int result = -1;
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
Gdiplus::GetImageEncodersSize(&num, &size);
if(size)
{
Gdiplus::ImageCodecInfo* codec = (Gdiplus::ImageCodecInfo*)(malloc(size));
GetImageEncoders(num, size, codec);
for(UINT j = 0; j < num; ++j)
if(wcscmp(codec[j].MimeType, format) == 0)
{
*clsid = codec[j].Clsid;
result = j;
}
free(codec);
}
return result;
}
bool convert_grayscale(const wchar_t *file_in, const wchar_t *file_out)
{
CStringW extension = PathFindExtensionW(file_out);
extension.Remove(L'.');
extension.MakeLower();
if(extension == L"jpg") extension = L"jpeg";
extension = L"image/" + extension;
CLSID clsid;
if(GetEncoderClsid(extension, &clsid) == -1)
return false;
Gdiplus::Bitmap source(file_in);
if(source.GetLastStatus() != Gdiplus::Status::Ok)
return false;
Gdiplus::REAL w = (Gdiplus::REAL)source.GetWidth();
Gdiplus::REAL h = (Gdiplus::REAL)source.GetHeight();
Gdiplus::RectF rect(0, 0, w, h);
Gdiplus::Bitmap copy((INT)w, (INT)h, source.GetPixelFormat());
Gdiplus::ColorMatrix matrix =
{
.3f, .3f, .3f, 0, 0,
.6f, .6f, .6f, 0, 0,
.1f, .1f, .1f, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 1
};
Gdiplus::ImageAttributes attr;
attr.SetColorMatrix(&matrix,
Gdiplus::ColorMatrixFlagsDefault, Gdiplus::ColorAdjustTypeBitmap);
Gdiplus::Graphics gr(©);
gr.DrawImage(&source, rect, 0, 0, w, h, Gdiplus::UnitPixel, &attr);
auto st = copy.Save(file_out, &clsid);
return st == Gdiplus::Status::Ok;
}
...
convert_grayscale(L"source.jpg", L"destination.jpg");
I want to load an image using OpenCV and then display it on a window.
I know how to load an image using opencv and how to create a window using win32 but how do I go about putting the image / mat from Opencv on the window afterwards?
This is how I load the image from opencv:
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
string imageName("C:/image.jpg"); // by default
if (argc > 1)
{
imageName = argv[1];
}
Mat image;
image = imread(imageName.c_str(), IMREAD_COLOR);
if (image.empty())
{
cout << "Could not open or find the image" << std::endl;
return -1;
}
namedWindow("Display window", WINDOW_AUTOSIZE);
imshow("Display window", image);
waitKey(0);
return 0;
}
EDIT: The reason I want to do this is actually not to create a window during runtime and then display the image on it, but rather I want to find a window using win32's FindWindow function and then draw an image on that :D
I'm using this pretty often with my MFC projects. If you only have hwnd, not CWnd, then you may have to change a bit.
This works both with 8-bit RGB color and 1-channel monochrome image.
void DrawImage( CWnd *wnd, int width, int height, int bpp, const unsigned char *buffer)
{
RECT rect;
wnd->GetWindowRect(&rect);
CDC *dc = wnd->GetDC();
if( bpp == 3) // BGR
{
BITMAPINFO bmpinfo;
memset(&bmpinfo, 0, sizeof(bmpinfo));
bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpinfo.bmiHeader.biBitCount = 24;
bmpinfo.bmiHeader.biClrImportant = 0;
bmpinfo.bmiHeader.biClrUsed = 0;
bmpinfo.bmiHeader.biCompression = BI_RGB;
bmpinfo.bmiHeader.biWidth = width;
bmpinfo.bmiHeader.biHeight = -height;
bmpinfo.bmiHeader.biPlanes = 1;
bmpinfo.bmiHeader.biSizeImage = 0;
bmpinfo.bmiHeader.biXPelsPerMeter = 100;
bmpinfo.bmiHeader.biYPelsPerMeter = 100;
::SetStretchBltMode( dc->GetSafeHdc(), COLORONCOLOR);
::StretchDIBits( dc->GetSafeHdc(),
0,
0,
rect.right - rect.left,
rect.bottom - rect.top,
0,
0,
width,
height,
buffer,
&bmpinfo,
DIB_RGB_COLORS,
SRCCOPY);
}
else if ( bpp == 1) // monochrome.
{
char bitmapInfoBuf[sizeof(BITMAPINFO) + 4 * 256];
BITMAPINFO* pBmpInfo = (BITMAPINFO*)bitmapInfoBuf;
memset(pBmpInfo, 0, sizeof(BITMAPINFO) + 4 * 256);
pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBmpInfo->bmiHeader.biWidth = width;
pBmpInfo->bmiHeader.biHeight = -height;
pBmpInfo->bmiHeader.biCompression = BI_RGB;
pBmpInfo->bmiHeader.biPlanes = 1;
pBmpInfo->bmiHeader.biBitCount = 8;
for(int i = 0; i < 256; i++)
{
pBmpInfo->bmiColors[i].rgbBlue=i;
pBmpInfo->bmiColors[i].rgbGreen=i;
pBmpInfo->bmiColors[i].rgbRed=i;
pBmpInfo->bmiColors[i].rgbReserved=255;
}
::SetStretchBltMode( dc->GetSafeHdc(), COLORONCOLOR);
::StretchDIBits( dc->GetSafeHdc(),
0,
0,
rect.right - rect.left,
rect.bottom - rect.top,
0,
0,
width,
height,
buffer,
pBmpInfo,
DIB_RGB_COLORS,
SRCCOPY);
}
wnd->ReleaseDC(dc);
}
void DrawCVImage(cv::Mat image, CWnd *picture)
{
if (image.cols % 4 == 0)
{
DrawImage(picture,
image.cols,
image.rows,
image.channels() == 3 ? 3 : 1,
image.data);
}
else
{
Mat image2(image.rows, image.cols + ( 4 - image.cols % 4), image.type());
image2 = 0;
image.copyTo(image2(Rect(0, 0, image.cols, image.rows)));
DrawImage(picture,
image2.cols,
image2.rows,
image2.channels() == 3 ? 3 : 1,
image2.data);
}
}
Well...
Don't create a new window by calling "namedWindow()".
Then call imshow(nameOfExistingWindow, image).
Maybe it will work.