[vtkusers] Java servlet + Glassfish + volume rendering applications problem
Sebastien Jourdain
sebastien.jourdain at kitware.com
Wed Jan 21 11:17:20 EST 2015
You might run into a concurrency issue.
VTK is not thread safe, and the way Glassfish is handling servlet may
result in concurrency.
You did not notice it before because the rendering was faster in surface
mode. But for volume rendering, the server side might already be in a
Render() call when a new one occurs.
On a side note, why don't you use VTK Web or ParaViewWeb?
Seb
On Tue, Jan 20, 2015 at 10:43 PM, Emptystack <wulihouxiaoshuai at 163.com>
wrote:
> My Java servlet code is as following:
>
> package com.hou.service;
>
> import java.awt.image.BufferedImage;
> import java.io.File;
> import java.io.FileInputStream;
> import java.io.FileNotFoundException;
> import java.io.FileOutputStream;
> import java.io.IOException;
>
> import javax.imageio.ImageIO;
> import javax.servlet.ServletException;
> import javax.servlet.ServletOutputStream;
> import javax.servlet.http.HttpServlet;
> import javax.servlet.http.HttpServletRequest;
> import javax.servlet.http.HttpServletResponse;
> import javax.servlet.http.HttpSession;
>
> import com.hou.core.RenderContext;
> import com.sun.image.codec.jpeg.JPEGCodec;
> import com.sun.image.codec.jpeg.JPEGImageEncoder;
>
> import vtk.vtkActor;
> import vtk.vtkConeSource;
> import vtk.vtkJPEGWriter;
> import vtk.vtkNativeLibrary;
> import vtk.vtkPolyDataMapper;
> import vtk.vtkRenderWindow;
> import vtk.vtkRenderWindowInteractor;
> import vtk.vtkRenderer;
> import vtk.vtkUnsignedCharArray;
> import vtk.vtkWindowToImageFilter;
>
> public class Image extends HttpServlet {
>
> /**
> *
> */
> private static final long serialVersionUID = 1L;
>
> // private RenderContext renderContext;
>
> // Load VTK library and print which library was not properly loaded
> static {
> if (!vtkNativeLibrary.LoadAllNativeLibraries()) {
> for (vtkNativeLibrary lib :
> vtkNativeLibrary.values()) {
> if (!lib.IsLoaded()) {
>
> System.out.println(lib.GetLibraryName() + " not loaded");
> } else {
>
> System.out.println(lib.GetLibraryName() + " loaded");
> }
> }
> } else {
> System.out.println("All Libraries are loaded");
> }
> vtkNativeLibrary.DisableOutputWindow(null);
> }
>
> @Override
> protected void doGet(HttpServletRequest req, HttpServletResponse
> resp)
> throws ServletException, IOException {
> // TODO Auto-generated method stub
> // super.doGet(req, resp);
>
> HttpSession session = req.getSession(false);
>
> int count;
>
> vtkConeSource cone;
> vtkPolyDataMapper mapper;
> vtkActor actor;
> vtkRenderer renderer;
> vtkRenderWindow renderWindow;
> vtkRenderWindowInteractor interactor;
>
> String countKey = "count";
>
> String coneKey = "cone";
> String mapperKey = "mapper";
> String actorKey = "actor";
> String rendererKey = "renderer";
> String renderWindowKey = "renderWindow";
> String interactorKey = "interactor";
>
> if (session == null) {
> session = req.getSession(true);
>
> count = 0;
> session.setAttribute(countKey, count);
>
> cone = new vtkConeSource();
> cone.SetHeight(3.0);
> cone.SetRadius(1.0);
> cone.SetResolution(10);
> session.setAttribute(coneKey, cone);
>
> mapper = new vtkPolyDataMapper();
> mapper.SetInputConnection(cone.GetOutputPort());
> session.setAttribute(mapperKey, mapper);
>
> actor = new vtkActor();
> actor.SetMapper(mapper);
> session.setAttribute(actorKey, actor);
>
> renderer = new vtkRenderer();
> renderer.AddActor(actor);
> session.setAttribute(rendererKey, renderer);
>
> renderWindow = new vtkRenderWindow();
> renderWindow.SetSize(300, 300);
> renderWindow.SetOffScreenRendering(1);
> renderWindow.AddRenderer(renderer);
> session.setAttribute(renderWindowKey,
> renderWindow);
>
> interactor = new vtkRenderWindowInteractor();
> interactor.SetRenderWindow(renderWindow);
> session.setAttribute(interactorKey, interactor);
>
> interactor.Initialize();
> interactor.Render();
> } else {
> interactor =
> (vtkRenderWindowInteractor)session.getAttribute(interactorKey);
> renderWindow =
> (vtkRenderWindow)session.getAttribute(renderWindowKey);
>
> count = (int)session.getAttribute(countKey);
> count++;
> if (count == 1) {
> interactor.SetEventPosition(100, 100);
> interactor.SetLastEventPosition(100, 100);
> interactor.LeftButtonPressEvent();
> }
> else {
> interactor.LeftButtonPressEvent();
> interactor.SetEventPosition(110, 110);
> interactor.SetLastEventPosition(100, 100);
> interactor.MouseMoveEvent();
> }
> session.setAttribute(countKey, count);
> }
>
> int[] size = renderWindow.GetSize();
>
> vtkUnsignedCharArray pixelDataArray = new
> vtkUnsignedCharArray();
>
> renderWindow.GetPixelData(0, 0, size[0] - 1, size[1] - 1,
> 1-renderWindow.GetDoubleBuffer(),
> pixelDataArray);
>
> // convert unsigned char to byte,note the range of each
> primitive type
> byte[] bytePixelData = pixelDataArray.GetJavaArray();
>
> int[] RGBPixelData = new int[bytePixelData.length];
>
> // convert byte to unsigned and stored in RGBPixelData
> array
> for (int i = 0; i < RGBPixelData.length; i++) {
> RGBPixelData[i] = bytePixelData[i] & 0xff;
> }
> int[] pixelData = new int[size[0] * size[1]];
>
> int index = 0;
> int r, g, b;
>
> // The sequence of pixels is from left to right and from
> bottom to top,
> // so we need flip the RGB pixel
> // no A channel to avoid image distortion
> for (int row = size[1] - 1; row >= 0; row--) {
> for (int column = 0; column < size[0]; column++) {
> r = RGBPixelData[3 * (size[1] * row +
> column)];
> g = RGBPixelData[3 * (size[1] * row +
> column) + 1];
> b = RGBPixelData[3 * (size[1] * row +
> column) + 2];
>
> if (r > 255) {
> r = 255;
> }
> if (r < 0) {
> r = 0;
> }
> if (g > 255) {
> g = 255;
> }
> if (g < 0) {
> g = 0;
> }
> if (b > 255) {
> b = 255;
> }
> if (b < 0) {
> b = 0;
> }
>
> pixelData[index] = ((r & 0xff) << 16) |
> ((g & 0xff) << 8) | ((b &
> 0xff));
> index++;
> }
>
> }
> BufferedImage bi = new BufferedImage(size[0], size[1],
> BufferedImage.TYPE_INT_RGB);
> bi.getRaster().setDataElements(0, 0, size[0], size[1],
> pixelData);
>
> // get a ServletOutputStream for writing binary data
> ServletOutputStream so = resp.getOutputStream();
> // This creates an instance of a JPEGImageEncoder
> // that can be used to encode image data as JPEG Data
> streams.
> JPEGImageEncoder jie = JPEGCodec.createJPEGEncoder(so);
> // Encode a BufferedImage as a JPEG data stream
> jie.encode(bi);
>
> so.flush();
> }
> }
>
> I used a simple cone to test the rotation. And after several requests the
> cone can be rotated. So I replaced the code with the following volume
> rendering code :
>
> package com.hou.service;
>
> import java.awt.image.BufferedImage;
> import java.io.File;
> import java.io.FileInputStream;
> import java.io.FileNotFoundException;
> import java.io.FileOutputStream;
> import java.io.IOException;
>
> import javax.imageio.ImageIO;
> import javax.servlet.ServletException;
> import javax.servlet.ServletOutputStream;
> import javax.servlet.http.HttpServlet;
> import javax.servlet.http.HttpServletRequest;
> import javax.servlet.http.HttpServletResponse;
> import javax.servlet.http.HttpSession;
>
> import com.hou.auxiliary.VolumeMapperType;
> import com.hou.convertor.DicomImageImport;
> import com.hou.core.RenderContext;
> import com.hou.prop.ViewProp;
> import com.sun.image.codec.jpeg.JPEGCodec;
> import com.sun.image.codec.jpeg.JPEGImageEncoder;
>
> import vtk.vtkActor;
> import vtk.vtkColorTransferFunction;
> import vtk.vtkConeSource;
> import vtk.vtkDICOMImageReader;
> import vtk.vtkGPUVolumeRayCastMapper;
> import vtk.vtkImageData;
> import vtk.vtkImageShiftScale;
> import vtk.vtkJPEGWriter;
> import vtk.vtkNativeLibrary;
> import vtk.vtkPiecewiseFunction;
> import vtk.vtkPlaneSource;
> import vtk.vtkPolyDataMapper;
> import vtk.vtkRenderWindow;
> import vtk.vtkRenderWindowInteractor;
> import vtk.vtkRenderer;
> import vtk.vtkSmartVolumeMapper;
> import vtk.vtkUnsignedCharArray;
> import vtk.vtkVolume;
> import vtk.vtkVolumeMapper;
> import vtk.vtkVolumeProperty;
> import vtk.vtkVolumeRayCastMIPFunction;
> import vtk.vtkVolumeRayCastMapper;
> import vtk.vtkWindowToImageFilter;
>
> public class Image extends HttpServlet {
>
> /**
> *
> */
> private static final long serialVersionUID = 1L;
>
> // private RenderContext renderContext;
>
> // Load VTK library and print which library was not properly loaded
> static {
> if (!vtkNativeLibrary.LoadAllNativeLibraries()) {
> for (vtkNativeLibrary lib :
> vtkNativeLibrary.values()) {
> if (!lib.IsLoaded()) {
>
> System.out.println(lib.GetLibraryName() + " not loaded");
> } else {
>
> System.out.println(lib.GetLibraryName() + " loaded");
> }
> }
> } else {
> System.out.println("All Libraries are loaded");
> }
> vtkNativeLibrary.DisableOutputWindow(null);
> }
>
> @Override
> protected void doGet(HttpServletRequest req, HttpServletResponse
> resp)
> throws ServletException, IOException {
> // TODO Auto-generated method stub
> // super.doGet(req, resp);
>
> HttpSession session = req.getSession(false);
>
> int count;
>
> vtkDICOMImageReader reader;
> vtkGPUVolumeRayCastMapper mapper;
> vtkColorTransferFunction colorTransferFunction;
> vtkPiecewiseFunction opacityFunction;
> vtkVolumeProperty volumeProperty;
> vtkVolume volume;
> vtkRenderer renderer;
> vtkRenderWindow renderWindow;
> vtkRenderWindowInteractor interactor;
>
> String countKey = "count";
>
> String readerKey = "reader";
> String colorTFKey = "colorTF";
> String opacityTFKey = "opacityTF";
> String mapperKey = "mapper";
> String volumePropertyKey = "volumeProperty";
> String volumeKey = "volume";
> String rendererKey = "renderer";
> String renderWindowKey = "renderWindow";
> String interactorKey = "interactor";
>
> if (session == null) {
> session = req.getSession(true);
>
> reader = new vtkDICOMImageReader();
> reader.SetDirectoryName("/home/garnett/image/CT");
> reader.Update();
> session.setAttribute(readerKey, reader);
>
>
> colorTransferFunction = new
> vtkColorTransferFunction();
> colorTransferFunction.AddRGBPoint(-3024, 0.0, 0.0,
> 0.0);
> colorTransferFunction.AddRGBPoint(42.9, 0.55,
> 0.25, 0.15);
> colorTransferFunction.AddRGBPoint(184.4, 0.92,
> 0.64, 0.06);
> colorTransferFunction.AddRGBPoint(277.64, 1.0,
> 0.88, 0.62);
> colorTransferFunction.AddRGBPoint(1430, 1.0, 0.99,
> 0.95);
> session.setAttribute(colorTFKey,
> colorTransferFunction);
>
> opacityFunction = new vtkPiecewiseFunction();
> opacityFunction.AddPoint(-3024, 0.0);
> opacityFunction.AddPoint(42.9, 0.0);
> opacityFunction.AddPoint(163.5, 0.429);
> opacityFunction.AddPoint(277.64, 0.777);
> opacityFunction.AddPoint(1430, 0.758);
> session.setAttribute(opacityTFKey,
> opacityFunction);
>
> volumeProperty = new vtkVolumeProperty();
> volumeProperty.SetColor(colorTransferFunction);
> volumeProperty.SetScalarOpacity(opacityFunction);
> volumeProperty.SetInterpolationTypeToLinear();
> volumeProperty.ShadeOn();
> volumeProperty.SetAmbient(0.1);
> volumeProperty.SetDiffuse(0.9);
> volumeProperty.SetSpecular(0.2);
> volumeProperty.SetSpecularPower(10.0);
>
> volumeProperty.SetScalarOpacityUnitDistance(0.8919);
> session.setAttribute(volumePropertyKey,
> volumeProperty);
>
> mapper = new vtkGPUVolumeRayCastMapper();
> mapper.SetBlendModeToComposite();
> mapper.SetInput(reader.GetOutput());
> mapper.Update();
> session.setAttribute(mapperKey, mapper);
>
> volume = new vtkVolume();
> volume.SetMapper(mapper);
> volume.SetProperty(volumeProperty);
> session.setAttribute(volumeKey, volume);
>
> count = 0;
> session.setAttribute(countKey, count);
>
> renderer = new vtkRenderer();
> renderer.AddVolume(volume);
> session.setAttribute(rendererKey, renderer);
>
> renderWindow = new vtkRenderWindow();
> renderWindow.SetSize(300, 300);
> renderWindow.SetOffScreenRendering(1);
> renderWindow.AddRenderer(renderer);
> session.setAttribute(renderWindowKey,
> renderWindow);
>
> interactor = new vtkRenderWindowInteractor();
> interactor.SetRenderWindow(renderWindow);
> session.setAttribute(interactorKey, interactor);
>
> interactor.Initialize();
> interactor.Render();
> } else {
> interactor =
> (vtkRenderWindowInteractor)session.getAttribute(interactorKey);
> renderWindow =
> (vtkRenderWindow)session.getAttribute(renderWindowKey);
>
> count = (int)session.getAttribute(countKey);
> count++;
> if (count == 1) {
> interactor.SetEventPosition(100, 100);
> interactor.SetLastEventPosition(100, 100);
> interactor.LeftButtonPressEvent();
> interactor.LeftButtonReleaseEvent();
> }
> else {
> interactor.LeftButtonPressEvent();
> interactor.SetEventPosition(110, 110);
> interactor.SetLastEventPosition(100, 100);
> interactor.MouseMoveEvent();
> interactor.LeftButtonReleaseEvent();
> }
> session.setAttribute(countKey, count);
> }
>
> int[] size = renderWindow.GetSize();
>
> vtkUnsignedCharArray pixelDataArray = new
> vtkUnsignedCharArray();
>
> renderWindow.GetPixelData(0, 0, size[0] - 1, size[1] - 1,
> 1-renderWindow.GetDoubleBuffer(),
> pixelDataArray);
>
> // convert unsigned char to byte,note the range of each
> primitive type
> byte[] bytePixelData = pixelDataArray.GetJavaArray();
>
> int[] RGBPixelData = new int[bytePixelData.length];
>
> // convert byte to unsigned and stored in RGBPixelData
> array
> for (int i = 0; i < RGBPixelData.length; i++) {
> RGBPixelData[i] = bytePixelData[i] & 0xff;
> }
> int[] pixelData = new int[size[0] * size[1]];
>
> int index = 0;
> int r, g, b;
>
> // The sequence of pixels is from left to right and from
> bottom to top,
> // so we need flip the RGB pixel
> // no A channel to avoid image distortion
> for (int row = size[1] - 1; row >= 0; row--) {
> for (int column = 0; column < size[0]; column++) {
> r = RGBPixelData[3 * (size[1] * row +
> column)];
> g = RGBPixelData[3 * (size[1] * row +
> column) + 1];
> b = RGBPixelData[3 * (size[1] * row +
> column) + 2];
>
> if (r > 255) {
> r = 255;
> }
> if (r < 0) {
> r = 0;
> }
> if (g > 255) {
> g = 255;
> }
> if (g < 0) {
> g = 0;
> }
> if (b > 255) {
> b = 255;
> }
> if (b < 0) {
> b = 0;
> }
>
> pixelData[index] = ((r & 0xff) << 16) |
> ((g & 0xff) << 8) | ((b &
> 0xff));
> index++;
> }
>
> }
> BufferedImage bi = new BufferedImage(size[0], size[1],
> BufferedImage.TYPE_INT_RGB);
> bi.getRaster().setDataElements(0, 0, size[0], size[1],
> pixelData);
>
> // get a ServletOutputStream for writing binary data
> ServletOutputStream so = resp.getOutputStream();
> // This creates an instance of a JPEGImageEncoder
> // that can be used to encode image data as JPEG Data
> streams.
> JPEGImageEncoder jie = JPEGCodec.createJPEGEncoder(so);
> // Encode a BufferedImage as a JPEG data stream
> jie.encode(bi);
>
> so.flush();
> }
>
>
> }
>
> The first request still can get the image, but the second request failed.
> After some debugging works, I hav found that the problem happeneded at the
> interactor.MouseMoveEvent() method which invokes the
> vtkRenderWindowInteractor::Render() method. I don't know why it crashed at
> this place. Is there something wrong with my java servlet code? I have
> been
> confused with this problem for several months.
> Looking forward to your reply!
> Best fishes!
>
>
>
>
> --
> View this message in context:
> http://vtk.1045678.n5.nabble.com/Java-servlet-Glassfish-volume-rendering-applications-problem-tp5730017p5730190.html
> Sent from the VTK - Users mailing list archive at Nabble.com.
> _______________________________________________
> Powered by www.kitware.com
>
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>
> Please keep messages on-topic and check the VTK FAQ at:
> http://www.vtk.org/Wiki/VTK_FAQ
>
> Search the list archives at: http://markmail.org/search/?q=vtkusers
>
> Follow this link to subscribe/unsubscribe:
> http://public.kitware.com/mailman/listinfo/vtkusers
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtkusers/attachments/20150121/19ba8a46/attachment-0001.html>
More information about the vtkusers
mailing list