I want to render a simple image using vtkImageData in C++. I know that vtkImageDataGeometryFilter can do the job, but I'm asking if there is an other way to get the same result without using PolyData ? Here is my code, but I have an access violation reading while rendering, I don't know why...
vtkSmartPointer<vtkImageData> imageData =
vtkSmartPointer<vtkImageData>::New();
imageData->SetExtent(0, 5, 0, 5, 0, 1);
imageData->SetSpacing(1, 1, 1);
imageData->SetOrigin(0, 0, 0);
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
imageData->SetScalarComponentFromFloat(i,j,0,0,0);
}
}
vtkSmartPointer<vtkImageActor> imageActor =
vtkSmartPointer<vtkImageActor>::New();
imageActor->SetInputData(imageData);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(imageActor);
renderWindow->Render();
renderWindowInteractor->Start();
Thanks in advance for your help ^^
I found the bug finally. The line imageData->AllocateScalars(VTK_FLOAT, 3); was missing.
The following code displays a green square:
vtkSmartPointer<vtkImageData> imageData =
vtkSmartPointer<vtkImageData>::New();
imageData->SetExtent(0, 50, 0, 50, 0, 1);
imageData->SetSpacing(1, 1, 1);
imageData->SetOrigin(0, 0, 0);
imageData->AllocateScalars(VTK_FLOAT, 3);
for (int i = 0; i < 50; i++)
{
for (int j = 0; j < 50; j++)
{
imageData->SetScalarComponentFromFloat(i, j, 0, 1, 255);
}
}
vtkSmartPointer<vtkImageActor> imageActor =
vtkSmartPointer<vtkImageActor>::New();
imageActor->SetInputData(imageData);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(imageActor);
renderer->SetBackground(1, 0, 0.5);
renderWindow->Render();
renderWindowInteractor->Start();
Related
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.
I don't know how to resolve this problem, I want to use this function to make a soft-renderer engine to study 3D pipeline.
This is code:
#define GLFW_INCLUDE_GLU
#include <GLFW/glfw3.h>
int main(int argc, const char * argv[]) {
if(!glfwInit()){ //init error
return -1;
}
int width = 200; //screen width
int height = 200; //screen height
GLFWwindow* window = glfwCreateWindow(width, height, "Hello OpenGL", NULL, NULL); //create window
if(!window){ //create window fail
glfwTerminate();
return -1;
}
u_char* pixels = new unsigned char[width * height * 4]; //buffer
uint index; //temp
//set pixel
for (int count_a = 0; count_a < width; count_a++) {
for (int count_b = 0; count_b < height; count_b++) {
index = count_b * width + count_a;
pixels[index * 4 + 0] = 255; //red pixel
pixels[index * 4 + 1] = 0; //green
pixels[index * 4 + 2] = 0; //blue
pixels[index * 4 + 3] = 255; //alpha
}
}
glfwMakeContextCurrent(window);
while (!glfwWindowShouldClose(window)) { //close window
glClearColor(1.0, 1.0, 1.0, 1.0); //clear screen by white pixel
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2f(-1, -1); //set origin to screen bottom left
//glPixelZoom(2, 2); //if i use this function. renderer is right.
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); //draw pixel
glfwSwapBuffers(window); //swap buffer
}
glfwTerminate();
return 0;
}
I was having this issue when using GLUT, so I came to this before and while reimplementing my code using GLFW. This issue is caused by the Retina display (as a lot of other sources have figured out), and the following ended up fixing it for me:
int width = 1360*2; //screen width
int height = 768*2; //screen height
GLFWwindow* window = glfwCreateWindow(width/2, height/2, "Hello OpenGL", NULL, NULL); //create window
// ...
Here's my code, using SDL 2.0.4 on OSX 10.11.4:
SDL_Surface *output_surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0);
SDL_Texture *output_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, width, height);
SDL_Color c[256];
// Setting each color to red as a test.
for(u8 i = 255; i--;) {
c[i].r = 255;
c[i].g = 0;
c[i].b = 0;
}
SDL_SetPaletteColors(output_surface->format->palette, c, 0, 256);
Then later...
SDL_Rect r = {
.x = 0,
.y = 0,
.w = width,
.h = height
};
// Doesn't fill with red.
SDL_FillRect(output_surface, &r, 4);
SDL_UpdateTexture(output_texture, NULL, output_surface->pixels, output_surface->pitch);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, output_texture, NULL, NULL);
SDL_RenderPresent(renderer);
What I would expect to see is the full window all red but I'm getting something entirely different. Changing the color number passed to SDL_FillRect shows that I'm getting a grayscale palette (0 is black, 255 is white) even though SDL_SetPaletteColors doesn't return an error and i've looped through output_surface->format->palette->colors to verify the palette's been changed.
What am I missing here?
edit: I was asked to post an entire program. Here it is:
int main(int argc, const char *argv[]) {
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Surface *output_surface = NULL;
SDL_Texture *output_texture = NULL;
int width = 640;
int height = 480;
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0) return 0;
window = SDL_CreateWindow("Sample", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
output_surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0);
output_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, width, height);
SDL_Color c[256];
for(u8 i = 255; i--;) {
c[i].r = 255;
c[i].g = 0;
c[i].b = 0;
c[i].a = 255;
}
SDL_SetPaletteColors(output_surface->format->palette, c, 0, 255);
SDL_Rect r = {
.x = 0,
.y = 0,
.w = width,
.h = height
};
bool running = true;
while(running) {
SDL_Event event;
while(SDL_PollEvent(&event)) {
switch(event.type){
case SDL_KEYDOWN:
running = false;
break;
}
}
SDL_FillRect(output_surface, &r, 124);
SDL_UpdateTexture(output_texture, NULL, output_surface->pixels, output_surface->pitch);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, output_texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_FreeSurface(output_surface);
SDL_DestroyTexture(output_texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Passing 0 to SDL_FillRect is black, 255 is white, and any number in-between is a shade of grey.
Alright, found the solution.
Remove this line:
output_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, width, height);
And instead add this line somewhere after the call to SDL_SetPaletteColors or after you change the surfaces' pixels (like in the game loop):
output_texture = SDL_CreateTextureFromSurface(renderer, output_surface);
How using SDL_CreateTexture create transparent texture? By default I'm creating texure with such code:
SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,SDL_TEXTUREACCESS_TARGET, x, y);
And then I'm paining on this texture with redirecting output to this texture. However at the end what I want to render this on screen any (nonupdated) pixel is black.
I have tried different ways with using of:
SDL_RenderClear(_Renderer);
or even with drawing and on created texture with painting transparent Rect with different blending modes but all I had as a result was still nontransparent texture :/
SDL_Rect rect={0,0,Width,Height};
SDL_SetRenderDrawBlendMode(_Renderer,SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(_Renderer,255,255,255,0);
SDL_RenderFillRect(_Renderer,&rect);
To be more specific:
//this->texDefault.get()->get() = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,SDL_TEXTUREACCESS_TARGET, x, y);
SDL_SetRenderTarget(_Renderer.get()->get(), this->texDefault.get()->get());
SDL_SetRenderDrawBlendMode(this->_Renderer.get()->get(),SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(this->_Renderer.get()->get(),255,0,255,0);
SDL_RenderClear(this->_Renderer.get()->get());
//SDL_Rect rect={0,0,Width,Height};
//SDL_SetRenderDrawColor(this->_Renderer.get()->get(),255,255,255,255);
//SDL_RenderFillRect(this->_Renderer.get()->get(),&rect);
//SDL_RenderClear(this->_Renderer.get()->get());
//SDL_SetRenderDrawBlendMode(this->_Renderer.get()->get(),SDL_BLENDMODE_NONE);
SDL_SetRenderTarget(_Renderer.get()->get(), NULL);
SDL_Rect rect= {relTop+Top,relLeft+Left,Height,Width};
SDL_SetRenderDrawBlendMode(this->_Renderer.get()->get(),SDL_BLENDMODE_BLEND);
SDL_RenderCopy(this->_Renderer.get()->get(), this->texDefault->get(), NULL, &rect);
This code is always producing nontransparent Texture independenty what i will set for blending and alpha
The result is :
Maybe there is some other simple method to create transparent empty texture in SDL2 something like x/y-sized fully transparent png but loading having such image in file is little bit pointless :/
First, you need to set renderer blend mode: SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);.
Second, you need to set texture blend mode: SDL_SetTextureBlendMode(textures[i], SDL_BLENDMODE_BLEND);.
Here is working example I created. You can use keys A and S to change alpha channel of third texture, which is invisible at start of the application.
#include <iostream>
#include <vector>
#include <SDL.h>
void fillTexture(SDL_Renderer *renderer, SDL_Texture *texture, int r, int g, int b, int a)
{
SDL_SetRenderTarget(renderer, texture);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer, r, g, b, a);
SDL_RenderFillRect(renderer, NULL);
}
void prepareForRendering(SDL_Renderer *renderer)
{
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
}
void checkSdlError()
{
const char *sdlError = SDL_GetError();
if(sdlError && *sdlError)
{
::std::cout << "SDL ERROR: " << sdlError << ::std::endl;
}
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_HAPTIC);
SDL_Window *window = SDL_CreateWindow("SDL test",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
320, 240,
SDL_WINDOW_OPENGL);
SDL_Renderer *renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
const int width = 50;
const int height = 50;
::std::vector<SDL_Texture*> textures;
SDL_Texture *redTexture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
textures.push_back(redTexture);
SDL_Texture *greenTexture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
textures.push_back(greenTexture);
SDL_Texture *purpleTexture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
textures.push_back(purpleTexture);
// Here is setting the blend mode for each and every used texture:
for(int i = 0; i < textures.size(); ++i)
{
SDL_SetTextureBlendMode(textures[i], SDL_BLENDMODE_BLEND);
}
int purpleAlpha = 0;
fillTexture(renderer, redTexture, 255, 0, 0, 255);
fillTexture(renderer, greenTexture, 0, 255, 0, 128);
fillTexture(renderer, purpleTexture, 255, 0, 255, purpleAlpha);
prepareForRendering(renderer);
bool running = true;
while(running)
{
SDL_Rect rect;
rect.w = width;
rect.h = height;
SDL_RenderClear(renderer);
rect.x = 50;
rect.y = 50;
SDL_RenderCopy(renderer, redTexture, NULL, &rect);
rect.x = 75;
rect.y = 70;
SDL_RenderCopy(renderer, greenTexture, NULL, &rect);
rect.x = 75;
rect.y = 30;
SDL_RenderCopy(renderer, purpleTexture, NULL, &rect);
SDL_RenderPresent(renderer);
// Process events
{
SDL_Event event;
while(SDL_PollEvent(&event) == 1)
{
if(event.type == SDL_QUIT)
{
running = false;
}
else if(event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE:
running = false;
break;
case SDLK_a:
purpleAlpha = ::std::max(purpleAlpha - 32, 0);
fillTexture(renderer, purpleTexture, 255, 0, 255, purpleAlpha);
prepareForRendering(renderer);
::std::cout << "Alpha: " << purpleAlpha << ::std::endl;
break;
case SDLK_s:
purpleAlpha = ::std::min(purpleAlpha + 32, 255);
fillTexture(renderer, purpleTexture, 255, 0, 255, purpleAlpha);
prepareForRendering(renderer);
::std::cout << "Alpha: " << purpleAlpha << ::std::endl;
break;
}
}
}
checkSdlError();
}
}
for(int i = 0; i < textures.size(); ++i)
{
SDL_DestroyTexture(textures[i]);
}
textures.clear();
SDL_DestroyRenderer(renderer);
renderer = NULL;
SDL_DestroyWindow(window);
window = NULL;
SDL_Quit();
checkSdlError();
return 0;
}
EDIT: Completely rewritten the answer, original one basically contained blend mode of renderer.
I have the following code where i plot points in 3d space:
vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();
for(int in = 0; in<x.size(); in++)
{
points->InsertNextPoint (x[in], y[in], ry[in]);
}
vtkSmartPointer<vtkPolyData> pointsPolydata =
vtkSmartPointer<vtkPolyData>::New();
pointsPolydata->SetPoints(points);
vtkSmartPointer<vtkVertexGlyphFilter> vertexFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
#if VTK_MAJOR_VERSION <= 5
vertexFilter->SetInputConnection(pointsPolydata->GetProducerPort());
#else
vertexFilter->SetInputData(pointsPolydata);
#endif
vertexFilter->Update();
vtkSmartPointer<vtkPolyData> polydata =
vtkSmartPointer<vtkPolyData>::New();
polydata->ShallowCopy(vertexFilter->GetOutput());
// Setup colors
unsigned char red[3] = {255, 0, 0};
unsigned char green[3] = {0, 255, 0};
unsigned char blue[3] = {0, 0, 255};
vtkSmartPointer<vtkUnsignedCharArray> colors =
vtkSmartPointer<vtkUnsignedCharArray>::New();
colors->SetNumberOfComponents(3);
colors->SetName ("Colors");
colors->InsertNextTupleValue(red);
colors->InsertNextTupleValue(green);
colors->InsertNextTupleValue(blue);
polydata->GetPointData()->SetScalars(colors);
// Visualization
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
#if VTK_MAJOR_VERSION <= 5
mapper->SetInputConnection(polydata->GetProducerPort());
#else
mapper->SetInputData(polydata);
#endif
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetPointSize(5);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(actor);
this->ui->qvtkWidget->GetRenderWindow()->AddRenderer(renderer);
renderWindowInteractor->Start();
When I get the resulting plot. All the points are plotted, but is hard to see anything due to the default scale. What I'm not sure is how to zoom in the view on the z axis. Any help would be appreciated.