How to create a HSV-Histogram with JavaCV - scala

I'm new in JavaCV and want to create a Histogram from a image.
I tried to translate some C++ code into Java but JavaCV don't have methods like cvCVtPixToPlane.
Can someone help me to create a histogram?

a translatet OpenCV-Code from the OpenCV-Wiki must be run.
I give you my code snipet to create a 1D-Diagram from the h-channel:
private CvHistogram getHueHistogram(IplImage image){
if(image==null || image.nChannels()<3) new Exception("Error!");
IplImage hsvImage= cvCreateImage(image.cvSize(), image.depth(), 3);
cvCvtColor(image, hsvImage, CV_BGR2HSV);
// Split the 3 channels into 3 images
IplImageArray hsvChannels = splitChannels(hsvImage);
//bins and value-range
numberOfBins=255;
float minRange= 0f;
float maxRange= 180f;
// Allocate histogram object
int dims = 1;
int[]sizes = new int[]{numberOfBins};
int histType = CV_HIST_ARRAY;
float[] minMax = new float[]{minRange, maxRange};
float[][] ranges = new float[][]{minMax};
int uniform = 1;
CvHistogram hist = cvCreateHist(dims, sizes, histType, ranges, uniform);
// Compute histogram
int accumulate = 1;
IplImage mask = null;
cvCalcHist(hsvChannels.position(0),hist, accumulate, null);
return hist;
}
And my splitChannels-Method, i used in this snipet:
private IplImageArray splitChannels(IplImage hsvImage) {
CvSize size = hsvImage.cvSize();
int depth=hsvImage.depth();
IplImage channel0 = cvCreateImage(size, depth, 1);
IplImage channel1 = cvCreateImage(size, depth, 1);
IplImage channel2 = cvCreateImage(size, depth, 1);
cvSplit(hsvImage, channel0, channel1, channel2, null);
return new IplImageArray(channel0, channel1, channel2);
}
If you want to draw a picture from the histogram you can iterate the bins. With cvQueryHistValue_1D() you can get the sum of pixels from bin_i

Related

MeshData GetVertexData has the incorrect length

I'm trying to optimize some mesh generation using MeshData & the Job System, but for some reason when I try to use 2 params in meshData.SetVertexBufferParams, the resulting meshData.GetVertexData is half the length it should be (I set the vertex count to 5120, but the resulting VertexData NativeArray is only 2560 items long).
When I force it to be double the length (SetVertexBufferParams(numVerts * 2, ...)), it creates a mesh that appears to treat the norms and vert positions as all position data and also makes the screen go black so no screen shot.
Here's my code:
// generate 256 height values
int[] arr = new int[256];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = (int) (Mathf.PerlinNoise(i / 16 / 16f, i % 16 / 16f) * 5);
}
// put it in a NativeArray
NativeArray<int> heights = new NativeArray<int>(arr, Allocator.TempJob);
// 4 verts per face * 5 faces = 20
int numVerts = heights.Length * 20; // this value is always 5120
// 2 tris per face * 5 daces * 3 indices = 30
int indices = heights.Length * 30;
// MeshData setup
Mesh.MeshDataArray meshDataArray = Mesh.AllocateWritableMeshData(1);
Mesh.MeshData meshData = meshDataArray[0];
meshData.SetVertexBufferParams(numVerts,
new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3, stream:0),
new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3, stream:1)
);
meshData.SetIndexBufferParams(indices, IndexFormat.UInt16);
// Create job
Job job = new Job
{
Heights = heights,
MeshData = meshData
};
// run job
job.Schedule().Complete();
// struct I'm using for vertex data
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct VData
{
public float3 Vert;
public float3 Norm;
}
// Here's some parts of the job
public struct Job : IJob
{
[ReadOnly]
public NativeArray<int> Heights;
public Mesh.MeshData MeshData;
public void Execute()
{
NativeArray<VData> Verts = MeshData.GetVertexData<VData>();
NativeArray<ushort> Tris = MeshData.GetIndexData<ushort>();
// loops from 0 to 255
for (int i = 0; i < Heights.Length; i++)
{
ushort t1 = (ushort)(w1 + 16);
// This indicates that Verts.Length is 2560 when it should be 5120
Debug.Log(Verts.Length);
int t = i * 30; // tris
int height = Heights[i];
// x and y coordinate in chunk
int x = i / 16;
int y = i % 16;
float3 up = new float3(0, 1, 0);
// This throws and index out of bounds error because t1 becomes larger than Verts.Length
Verts[t1] = new VData { Vert = new float3(x + 1, height, y + 1), Norm = up};
// ...
}
}
}
meshData.SetVertexBufferParams(numVerts,
new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3, stream:0),
new VertexAttributeDescriptor(VertexAttribute.Normal, VertexAttributeFormat.Float32, 3, stream:1)
);
Your SetVertexBufferParams here places VertexAttribute.Position and VertexAttribute.Normal on a separate streams thus halving the size of the buffer per stream and later the length of the buffers if buffer becomes reinterpreted with the wrong struct by mistake.
This is how documentation explains streams:
Vertex data is laid out in separate "streams" (each stream goes into a separate vertex buffer in the underlying graphics API). While Unity supports up to 4 vertex streams, most meshes use just one. Separate streams are most useful when some vertex attributes don't need to be processed, for example skinned meshes often use two vertex streams (one containing all the skinned data: positions, normals, tangents; while the other stream contains all the non-skinned data: colors and texture coordinates).
But why it might end up re-interpreted as half the length? Well, because of this line:
NativeArray<VData> Verts = MeshData.GetVertexData<VData>();
How? Because there is a implicit stream parameter value there (doc)
public NativeArray<T> GetVertexData(int stream = 0);
and it defaults to 0. So what happens here is this:
var Verts = Positions_Only.Reinterpret<Position_And_Normals>();
or in other words:
var Verts = NativeArray<float3>().Reinterpret<float3x2>();
case solved :T
TL;DR:
Change stream:1 to stream:0 so both vertex attributes end up on the same stream.
or var Positions = MeshData.GetVertexData<float3>(0); & var Normals = MeshData.GetVertexData<float3>(1);
or create a dedicated VData struct per stream var Stream0 = MeshData.GetVertexData<VStream0>(0); & var Stream1 = MeshData.GetVertexData<VStream1>(1);

Updating z-values for ILNumerics ILSurface

I'm a new ILNumerics Visualization Engine user and I'm still coming up to speed on how to use it well. I've searched extensively for how to update the z-values of an ILSurface and read the posts, but I'm still not clear on how to do this.
I'm able to generate a surface and set up a camera to view it (Hamyo Kutschbach told me that's the best way to ensure that the aspect ratios of the surface don't change when rotating the surface, which is important in my application). Here's the code that displays a sin(x)/x function:
// Generate the data
ILArray<double> z = SincFunc(rows, cols, 10, 50);
ILArray<double> x = new double[cols];
ILArray<double> y = new double[rows];
for (int i = 0; i < cols; i++)
x[i] = (double)i;
for (int i = 0; i < rows; i++)
y[i] = (double)i;
// create the scene
scene = new ILScene();
pointCloudSurface = new ILSurface(z, x, y)
{
Colormap = Colormaps.Jet,
UseLighting = true,
Wireframe = { Visible = false },
Children = { new ILColorbar()
{
Height = 0.5f,
Location = new PointF(0.95f, 0.05f),
Children = { new ILLabel("microns") { Position = new Vector3(0.5,1,0), Anchor = new PointF(0.5f,0) } } }
},
Alpha = 1.0f
};
// Configure the surface and display it
scene.Camera.Add(pointCloudSurface);
scene.Camera.Position = new Vector3(50, 50, 700);
scene.Camera.LookAt = new Vector3(50, 50, 0);
scene.Camera.Top = new Vector3(0, 0, 700);
scene.Camera.Projection = Projection.Perspective;
scene.Camera.ZNear = 1.0f;
scene.Camera.ZFar = 0.0f;
scene.Camera.Top = new Vector3(1, 0, 0);
// Turn off the Powered by ILNumerics label
scene.Screen.First<ILLabel>().Visible = false;
ilPanel1.Scene = scene;
ilPanel1.Configure();
ilPanel1.Refresh();
And it works well. So now I want to change the z-values and update the plot without closing ilPanel1 because this plot is embedded in a Windows Form. Advice would be appreciated! Hopefully other newbies will find this post useful as well.
After further rummaging around, I came across a method, UpdateColormapped(), that does the trick. It's placed near the end of the code above like this:
scene.Camera.First<ILSurface>().UpdateColormapped(z);
ilPanel1.Scene = scene;
ilPanel1.Configure();
ilPanel1.Refresh();
It can be found in the API documentation here: UpdateColormapped()
It can also change the x and y data and perform other mods, but it requires that the z data be a float array, so if you're working double precision, you'll have to take the appropriate steps to get it into a float array.

Read float values from RGBAFloat texture in Unity 3D

It seems people aren't discussing much around floating point textures. I used them to do some computations and then forward the result to another surface shader (to obtain some specific deformations) and that's cool, it always works for me if I digest the results in a shader but this time I need to get those values CPU side so I get a float[] array with the results (just after calling Graphics.Blit that fills the floating point texture). How can this be achieved?
On a side note: the only guy that I saw using this method so far is Keijiro, for example in his Kvant Wall; if you have other sources I'd be grateful if you let me know.
Incidentally, I know there are compute shaders and OpenCL and CUDA. This is the method I need now.
So I came up with this solution.
float[] DecodeFloatTexture()
{
Texture2D decTex = new Texture2D(resultBuffer.width, resultBuffer.height, TextureFormat.RGBAFloat, false);
RenderTexture.active = resultBuffer;
decTex.ReadPixels(new Rect(0, 0, resultBuffer.width, resultBuffer.height), 0, 0);
decTex.Apply();
RenderTexture.active = null;
Color[] colors = decTex.GetPixels();
// HERE YOU CAN GET ALL 4 FLOATS OUT OR JUST THOSE YOU NEED.
// IN MY CASE ALL 4 VALUES HAVE A MEANING SO I'M GETTING THEM ALL.
float[] results = new float[colors.Length*4];
for(int i=0; i<colors.Length; i++)
{
results[i * 4] = colors[i].r;
results[i * 4 + 1] = colors[i].g;
results[i * 4 + 2] = colors[i].b;
results[i * 4 + 3] = colors[i].a;
}
return results;
}
Alternatively, if what we need is not a float, GetRawTextureData can be used to then convert the bytes to the new type with System.BitConverter which gives some flexibility on the data you are passing from the shader (for example if your fragment shader is outputting half4). If you need float though the first method is better.
float[] DecodeFloatTexture()
{
Texture2D decTex = new Texture2D(resultBuffer.width, resultBuffer.height, TextureFormat.RGBAFloat, false);
RenderTexture.active = resultBuffer;
decTex.ReadPixels(new Rect(0, 0, resultBuffer.width, resultBuffer.height), 0, 0);
decTex.Apply();
RenderTexture.active = null;
byte[] bytes = decTex.GetRawTextureData();
float[] results = new float[resultBuffer.width * resultBuffer.height];
for (int i = 0; i < results.Length; i++)
{
int byteIndex = i * 4;
byte[] localBytes = new byte[] { bytes[i], bytes[i + 1], bytes[i + 2], bytes[i + 3] }; // converts 4 bytes to a float
results[i] = System.BitConverter.ToSingle(localBytes, 0);
}
return results;
}

3 channel depth image 1 channel

I have record a depth video using Kinect v2, when I extracted images using MATLAB then each image is 3 channel. Normally the images I saw are just 1 channel. Please any one tell me how can make this 3 channel image to 1 channel?
Here is the code of the depth part:
IplImage depth = new IplImage(512, 424, BitDepth.U16, 1);
CvVideoWriter DepthWriter;
Width = sensor.DepthFrameSource.FrameDescription.Width;
DHeight = sensor.DepthFrameSource.FrameDescription.Height;
WbDepth = new WriteableBitmap(DWidth, DHeight, 96, 96, PixelFormats.Gray16, null);
int depthshft = (int)SliderDepth.Value;
using (DepthFrame depthframe = frame.DepthFrameReference.AcquireFrame())
ushort* depthdata = (ushort*)depth.ImageData;
if (depthframe != null)
{
Depthdata = new ushort[DWidth * DHeight];
ushort[] Depthloc = new ushort[DWidth * DHeight];
depthframe.CopyFrameDataToArray(Depthdata);
for (int i = 0; i < DWidth * DHeight; i++)
{
Depthloc[i] = 0x1000;
}
colorspacePoint = new ColorSpacePoint[DWidth * DHeight];
depthspacePoint = new DepthSpacePoint[CWidth * CHeight];
sensor.CoordinateMapper.MapDepthFrameToColorSpace(Depthloc, colorspacePoint);
for (int y = 0; y < DHeight; y++)
{
for (int x = 0; x < DWidth; x++)
{
if (depthshft != 0)
{
Depthdata[y * DWidth + x] = (ushort)((Depthdata[y * DWidth + x]) << depthshft);
}
}
}
depth.CopyPixelData(Depthdata);
}
WbDepth.WritePixels(new Int32Rect(0, 0, DWidth, DHeight), Depthdata, strideDep, 0);
ImageDepth.Source = WbDepth;
if (depth != null && DepthWriter.FileName != null) Cv.WriteFrame(DepthWriter, depth);
Cv.ReleaseVideoWriter(DepthWriter);
if (CheckBox_saveD.IsChecked == true)
DepthWriter = new CvVideoWriter(string.Format("{1}\\Scene{0}_DepthRecord.avi", scene, TextBlock_saveloca.Text.ToString()), FourCC.Default, 30.0f, new CvSize(512, 424));
CheckBox_saveD.IsEnabled = false;
if (CheckBox_saveD.IsChecked == true) Cv.ReleaseVideoWriter(DepthWriter);
Thank you
Everyone so far is advising you to convert the (supposedly) color image to grayscale. I don't think you should do this.
The kinect gives you a "1 channel" image of depth values. If you have a color (3 channel) depth map, then something is wrong. Converting to gray scale will then make you lose depth information.
Instead, try to figure out why your image is loaded as gray scale in the first place. What is the source? Is the conversion maybe done by Matlab when reading the image? Can you then give it some flag to tell it not to?

Reduce border width on QR Codes generated by ZXing?

I'm using com.google.zxing.qrcode.QRCodeWriter to encode data and com.google.zxing.client.j2se.MatrixToImageWriter to generate the QR Code image. On a 400x400 image, there is about a 52 pixel wide border around the code. I'd like this border to be narrower, maybe 15 pixels, but I don't see anything in the API for doing that. Am I missing something in the documenation? Or would I need to process the image myself?
For reference, here is an example 400x400 QR Code produced with the ZXing library:
The QR spec requires a four module quiet zone and that's what zxing creates. (See QUIET_ZONE_SIZE in QRCodeWriter.renderResult.)
More recent versions of ZXing allow you to set the size of the quiet zone (basically the intrinsic padding of the QR code) by supplying an int value with the EncodeHintType.MARGIN key. Simply include it in the hints Map you supply to the Writer's encode(...) method, e.g.:
Map<EncodeHintType, Object> hints = new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 2); /* default = 4 */
If you change this, you risk lowering the decode success rate.
Even by setting EncodeHintType.MARGIN to 0, the algorithm that convert the QRCode "dot" matrix to pixels data can generate a small margin (the algorithm enforce a constant number of pixels per dots, so the margin pixel size is the remainder of the integer division of pixels size by QR-Code dot size).
However you can completely bypass this "dot to pixel" generation: you compute the QRCode dot matrix directly by calling the public com.google.zxing.qrcode.encoder.Encoder class, and generate the pixel image yourself. Code below:
// Step 1 - generate the QRCode dot array
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(1);
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
QRCode qrCode = Encoder.encode(what, ErrorCorrectionLevel.L, hints);
// Step 2 - create a BufferedImage out of this array
int width = qrCode.getMatrix().getWidth();
int height = qrCode.getMatrix().getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] rgbArray = new int[width * height];
int i = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
rgbArray[i] = qrCode.getMatrix().get(x, y) > 0 ? 0xFFFFFF : 0x000000;
i++;
} }
image.setRGB(0, 0, width, height, rgbArray, 0, width);
The conversion of the BufferedImage to PNG data is left as an exercise to the reader. You can also scale the image by setting a fixed number of pixels per dots.
It's usually more optimized that way, the generated image size is the smallest possible. If you rely on client to scale the image (w/o blur) you do not need more than 1 pixel per dot.
HashMap hintMap = new HashMap();
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
hintMap.put(EncodeHintType.MARGIN, -1);
no margin
UPDATE
Add dependencies (from comments)
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.2.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.2.0</version>
</dependency>
In swift you can:
let hints = ZXEncodeHints()
hints!.margin = NSNumber(int: 0)
let result = try writer.encode(code, format: format, width: Int32(size.width), height: Int32(size.height), hints: hints)
let cgImage = ZXImage(matrix: result, onColor: UIColor.blackColor().CGColor, offColor: UIColor.clearColor().CGColor).cgimage
let QRImage = UIImage(CGImage: cgImage)
My problem is that I need to generate a PNG image with a transparent background fixed to x * x pixels.
I find that whatever I do with EncodeHintType.MARGIN, these is always some unexpected margin.
After reading its source code, I find a way to fix my problem, this is my code. There is no margin in the output BufferedImage.
BufferedImage oriQrImg = getQrImg(CONTENT_PREFIX+userInfo, ErrorCorrectionLevel.L,BLACK);
BufferedImage scaledImg = getScaledImg(oriQrImg,REQUIRED_QR_WIDTH,REQUIRED_QR_HEIGHT);
private static BufferedImage getQrImg(String content, ErrorCorrectionLevel level, int qrColor) throws WriterException {
QRCode qrCode = Encoder.encode(content, level, QR_HINTS);
ByteMatrix input = qrCode.getMatrix();
int w=input.getWidth(),h=input.getHeight();
BufferedImage qrImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = qrImg.createGraphics();
qrImg = g2d.getDeviceConfiguration().createCompatibleImage(w,h, Transparency.BITMASK);
g2d.dispose();
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (input.get(x,y) == 1) {
qrImg.setRGB(x, y, qrColor);
}else{
qrImg.setRGB(x, y, Transparency.BITMASK);
}
}
}
return qrImg;
}
static BufferedImage getScaledImg(BufferedImage oriImg,int aimWidth,int aimHeight){
Image scaled = oriImg.getScaledInstance(aimWidth,aimHeight,SCALE_DEFAULT);
Graphics2D g2d = new BufferedImage(aimWidth,aimHeight, BufferedImage.TYPE_INT_RGB).createGraphics();
BufferedImage scaledImg = g2d.getDeviceConfiguration().createCompatibleImage(aimWidth,aimHeight, Transparency.BITMASK);
g2d.dispose();
scaledImg.createGraphics().drawImage(scaled, 0, 0,null);
return scaledImg;
}