I'm trying to merge a png with some transparency on a background:
Mat frg = Highgui.imread( "path/to/foreground/image.png" ), -1 );
Mat bkg = Highgui.imread( "path/to/background/image.png" ), -1 );
// Create mask from foreground.
Mat mask = new Mat( frg.width(), frg.height(), 24 );
double f[] = { 1, 1, 1, 0 };
double e[] = { 0, 0, 0, 0 };
for ( int y = 0; y < ( int )( frg.rows() ); ++y ) {
for ( int x = 0; x < ( int )( frg.cols() ); ++x ) {
double info[] = frg.get( y, x );
if ( info[3] > 0 ) {
mask.put( y, x, e );
} else {
mask.put( y, x, f );
}
}
}
// Copy foreground onto background using mask.
frg.copyTo( bkg, mask );
Highgui.imwrite( "path/to/result/image.png", bkg );
The resulting image is a kind of ghost showing the background image repeated various times and the foreground one in a corrupted way.
Any clues?
Thanks Rosa and for those interested, here is how I translated into Java the C++ snippet pointed out by Rosa:
private Mat overtrayImage( Mat background, Mat foreground ) {
// The background and the foreground are assumed to be of the same size.
Mat destination = new Mat( background.size(), background.type() );
for ( int y = 0; y < ( int )( background.rows() ); ++y ) {
for ( int x = 0; x < ( int )( background.cols() ); ++x ) {
double b[] = background.get( y, x );
double f[] = foreground.get( y, x );
double alpha = f[3] / 255.0;
double d[] = new double[3];
for ( int k = 0; k < 3; ++k ) {
d[k] = f[k] * alpha + b[k] * ( 1.0 - alpha );
}
destination.put( y, x, d );
}
}
return destination;
}
Related
I am trying to convert RGB values of an image and get the HSV values of it. I am trying to do this without using Color.RGBtoHSB because I don't like the float values I want the numbers to be in the range of 0-255. When I run this program my conversion algorithm prints out nothing even though I ask it to print out values.
public void splitChannels() {
Mat firstImage = Imgcodecs.imread("darkGreen.jpg");
Imgproc.cvtColor(firstImage, firstImage, Imgproc.COLOR_BGR2RGB);
int width = 20;
int height = 20;
Rect roi = new Rect(100,100, width, height);
Mat smallImg = new Mat(firstImage, roi);
Imgproc.cvtColor(smallImg,smallImg,Imgproc.COLOR_BGR2RGB);
// 3 channels in smallImg
int channels = smallImg.channels();
int totalBytes = (int)(smallImg.total() * smallImg.channels());
byte buff[] = new byte[totalBytes];
smallImg.get(0, 0, buff);
for (int i=0; i< height; i++) {
// stride is the number of bytes in a row of smallImg
int stride = channels * width;
for (int j=0; j<stride; j+=channels) {
int r = buff[(i * stride) + j];
int g = buff[(i * stride) + j + 1];
int b = buff[(i * stride) + j + 2];
RGBtoHSV(r, g, b);
}
}
}
private int[] RGBtoHSV(int r, int g, int b){
int computedH = 0;
int computedS = 0;
int computedV = 0;
int[] HSVarr = new int[3];
HSVarr[0] = computedH;
HSVarr[1] = computedS;
HSVarr[2] = computedV;
if(r< 0 || g< 0 || b< 0 || r> 255 || g>255 || b> 255){
System.err.println("RGB values must be in range 0 to 255");
}
r=r/255; g=g/255; b=b/255;
int minRGB = Math.min(r, Math.min(g, b));
int maxRGB = Math.max(r, Math.min(g, b));
// Black-gray-white
if(minRGB==maxRGB){
computedV = minRGB;
return HSVarr;
}
int d = (r==minRGB) ? g-b : ((b==minRGB) ? r-g : b-r);
int h = (r==minRGB) ? 3 : ((b==minRGB) ? 1 : 5);
computedH = 60*(h - d/(maxRGB - minRGB));
computedS = (maxRGB = minRGB)/maxRGB;
computedV = maxRGB;
System.out.println("H: " + computedH + " V: "+ computedS +" S: " + computedV);
return HSVarr;
}
I am trying to convert RGB values of an image and get the HSV values of it. I am trying to do this without using Color.RGBtoHSB because I don't like the float values.
Create a wrapper method for the Color.RGBtoHSB(...) method to convert the float values to the appropriate int values.
Something like:
import java.awt.*;
public class Main
{
public static void main(String[] args) throws Exception
{
int[] hsb = RGBtoHSB(0, 0, 255);
for (int value: hsb)
System.out.println( value );
}
public static int[] RGBtoHSB(int red, int green, int blue)
{
float[] hsbFloat = Color.RGBtoHSB(red, green, blue, null);
int[] hsbInt = new int[3];
hsbInt[0] = Math.round( hsbFloat[0] * 360 );
hsbInt[1] = Math.round( hsbFloat[1] * 100 );
hsbInt[2] = Math.round( hsbFloat[2] * 100 );
return hsbInt;
}
}
I use OpenGLES 2.0 draw a globe for Android, but I got wired texture drawing,Something wrong with the texture coordinates. Someone can help me? here is my sphere structure:
Sphere( Context context0, float r, int nSTACKS, int nSLICES ){
context = context0;
// get shader codes from res/raw/vshader and res/raw/fshader
vsCode = getShaderCode( GLES20.GL_VERTEX_SHADER );
fsCode = getShaderCode( GLES20.GL_FRAGMENT_SHADER );
program = GLES20.glCreateProgram(); // create empty OpenGL ES Program
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vsCode );
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fsCode );
GLES20.glAttachShader ( program, vertexShader ); // add the vertex shader to program
GLES20.glAttachShader(program, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(program); // creates OpenGL ES program executables
GLES20.glUseProgram( program);
createSphere (r, nSLICES, nSTACKS );
int nVertices = vertices.size();
int k = 0;
int m = nSTACKS;
int n = nSLICES;
float uTexture = 0;
float vTexture = 0;
// 2n(m-1) slices + 2(m-2)n stacks
nTriangles = 2 * n * (m - 1); //number of triangles
drawOrders = new short[nTriangles][3];
for ( int j = 0; j < n; j++ )
{
for ( int i = 0; i < m-1; i++ ) {
short j1 = (short)(j + 1);
if ( j == n - 1 ) j1 = 0; //wrap around
short ia = (short)( j * m + i ) ;
short ib = (short)( j * m + i + 1);
short ic = (short) (j1 * m + i );
short id = (short)( j1 * m + i + 1 );
drawOrders[k] = new short[3];
drawOrders[k][0] = ia;
drawOrders[k][1] = ib;
drawOrders[k][2] = ic;
k++;
drawOrders[k] = new short[3];
drawOrders[k][0] = ic;
drawOrders[k][1] = ib;
drawOrders[k][2] = id;
k++;
}
}
System.out.printf("k=%d, nTriangles=%d\n", k, nTriangles);
float sphereCoords[] = new float[3*nVertices];
k = 0;
for ( int i = 0; i < nVertices; i++ ) {
XYZ v = vertices.get ( i );
sphereCoords[k++] = v.x;
sphereCoords[k++] = v.y;
sphereCoords[k++] = v.z;
}
//vertexBuffer
ByteBuffer bb = ByteBuffer.allocateDirect(sphereCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(sphereCoords);
vertexBuffer.position(0);
//texture
float textureCoords[] = new float[2 * textures.size()];
k = 0;
for ( int i = 0; i < nVertices; i++ ) {
UV w = textures.get ( i );
textureCoords[k++] = w.u;
textureCoords[k++] = w.v;
}
//textureCoordBuffer
ByteBuffer bbtexture = ByteBuffer.allocateDirect(textureCoords.length * 4);
bbtexture.order(ByteOrder.nativeOrder());
textureCoordBuffer = bbtexture.asFloatBuffer();
textureCoordBuffer.put(textureCoords);
textureCoordBuffer.position(0);
sphereIndices = new ShortBuffer[nTriangles];
for ( int i = 0; i < nTriangles; i++) {
ByteBuffer bbIndices = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
drawOrders[i].length * 2);
bbIndices.order(ByteOrder.nativeOrder());
sphereIndices[i] = bbIndices.asShortBuffer();
sphereIndices[i].put( drawOrders[i] );
sphereIndices[i].position(0);
}
} // Sphere Constructor
private void createSphere ( float r, int nSlices, int nStacks )
{
double phi, theta;
XYZ p = new XYZ();
final double PI = 3.1415926;
final double TWOPI = 2 * PI;
UV t = new UV();
for ( int j = 0; j < nSlices; j++ ) {
phi = j * TWOPI / nSlices;
for ( int i = 0; i < nStacks; i++ ) {
theta = i * PI / (nStacks-1); //0 to pi
p.x = r * (float) (Math.sin ( theta ) * Math.cos(phi));
p.y = r * (float) (Math.sin ( theta ) * Math.sin(phi));
p.z = r * (float) Math.cos ( theta );
vertices.add ( new XYZ ( p ) );
t.u = (float)(p.x * 2 * PI);
t.v = (float)((p.y - 0.5) *PI);
textures.add(new UV(t));
}
}
}
And I got this texture:
Some one can help me to adjust the texture coords? Thanks~~~
I am making a heightmap using simplex noise. I am running into problems adjusting it to give a slight tendency to form an island. I am just working on getting the values to be correct before actually rendering the biomes and other features. I have run into the problem that my code, which should work to create this tendency to make an island in the middle only seems to work in one direction.
If there a particular reason for this? My class that deals with the smoothing out of the terrain does the same thing in the x and y directions, but only one works.
public class MapGenerator{
public double[][] toRender;
int maxHeight = 300;
public MapGenerator() {
int xResolution = 200;
int yResolution = 200;
double[][] result = new double[xResolution][yResolution];
for (int x = 0; x < xResolution; x++){
for (int y = 0; y < yResolution; y++){
result[x][y] = transformPoint(x, y, xResolution, yResolution, SimplexNoise.noise(x, y));
}
}
toRender = result;
}
private double transformPoint(int x, int y, int xSize, int ySize, double point){
System.out.println();
System.out.println(point);
point += 20 * Math.sin(x * Math.PI / xSize);
point += 20 * Math.sin(y * Math.PI / ySize);
System.out.println(point);
return point;
}
}
Images of the white noise:
With X and Y:
With only X (Y commented out):
[With only Y (X commented out):](Similar to X and Y, can't post link because of reputation.)
[Without X and Y:](Similar to only X, can't post link because of reputation.)
I'm not 100% where your error is. It could be in your noise routine. To debug this, I removed the call to noise and substituted a constant value of 0.5. Then I got the rest of it working so I saw a white halo in the center of the image. Then I added the noise call back. (Note I'm using my own SimplexNoise here.)
So the problem is either in your bounds (Math.min( 1.0, point )) or in your graphics display (which you don't show) or in your SimplexNoise (which you also don't show).
import SimpleUtils.noise.SimplexNoise;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
/**
*
* #author Brenden Towey
*/
public class MapGenerator
{
public static void main( String[] args )
{
SwingUtilities.invokeLater( new Runnable()
{
public void run()
{
JFrame frame = new JFrame();
frame.add( new JLabel( new ImageIcon( new MapGenerator().toImage() )));
frame.pack();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
} );
}
public double[][] toRender;
int maxHeight = 300;
int xResolution = 200;
int yResolution = 200;
public MapGenerator()
{
double[][] result = new double[ xResolution ][ yResolution ];
SimplexNoise noise = new SimplexNoise();
for( int x = 0; x < xResolution; x++ )
for( int y = 0; y < yResolution; y++ )
result[x][y] = transformPoint( x, y, noise.noise(x, y) );
toRender = result;
}
private double transformPoint( int x, int y, double point )
{
point += 2 * Math.sin( x * Math.PI / xResolution )/2.0;
point += 2 * Math.sin( y * Math.PI / yResolution )/2.0;
return Math.min( 1.0, point);
}
public Image toImage()
{
BufferedImage image = new BufferedImage( xResolution,
yResolution, BufferedImage.TYPE_INT_RGB );
for( int x = 0; x < xResolution; x++ )
for( int y = 0; y < yResolution; y++ )
image.setRGB( x, y, greyScale( toRender[x][y] ) );
return image;
}
private int greyScale( double toRender )
{
int scale = (int) ( 255 * toRender );
return scale + (scale << 8) + (scale << 16);
}
}
I try to make a screenshot of my game according to this article:
https://github.com/libgdx/libgdx/wiki/Taking-a-Screenshot
It seams that there is problem with black color in PNG conversion.
My screenshots looks as follow:
should be:
is:
Here is detailed view:
There is a strange color instead of shadow around a leaf.
Did anyone have a similar problem?
I resolved this problem by implementing platform specific mechanism - it's different for android and desktop applications.
You can find more about platform specific code in libgdx here.
Here is the interface for android:
public interface ScreenshotPixmap {
public void saveScreenshot(FileHandle fileHandle);
}
And implementation:
public class AndroidScreenshotPixmap implements ScreenshotPixmap {
public Pixmap getScreenshot( int x, int y, int w, int h, boolean flipY ) {
Gdx.gl.glPixelStorei( GL20.GL_PACK_ALIGNMENT, 1 );
final Pixmap pixmap = new Pixmap( w, h, Pixmap.Format.RGBA8888 );
ByteBuffer pixels = pixmap.getPixels();
Gdx.gl.glReadPixels( x, y, w, h, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixels );
final int numBytes = w * h * 4;
byte[] lines = new byte[numBytes];
if ( flipY ) {
final int numBytesPerLine = w * 4;
for ( int i = 0; i < h; i++ ) {
pixels.position( (h - i - 1) * numBytesPerLine );
pixels.get( lines, i * numBytesPerLine, numBytesPerLine );
}
pixels.clear();
pixels.put( lines );
} else {
pixels.clear();
pixels.get( lines );
}
return pixmap;
}
public int[] pixmapToIntArray( Pixmap pixmap ) {
int w = pixmap.getWidth();
int h = pixmap.getHeight();
int dest = 0;
int[] raw = new int[w * h];
for ( int y = 0; y < h; y++ ) {
for ( int x = 0; x < w; x++ ) {
int rgba = pixmap.getPixel( x, y );
raw[dest++] = 0xFF000000 | ( rgba >> 8 );
}
}
return raw;
}
public void savePNG( int[] colors, int width, int height, OutputStream stream ) {
Bitmap bitmap = Bitmap.createBitmap( colors, width, height, Bitmap.Config.ARGB_8888 );
bitmap.compress( Bitmap.CompressFormat.PNG, 100, stream );
}
#Override
public void saveScreenshot(FileHandle fileHandle) {
Pixmap pixmap = getScreenshot(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
OutputStream stream = fileHandle.write(false);
savePNG(pixmapToIntArray(pixmap), Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), stream);
}
}
Good luck.
I've found a method on the Internet to convert RGB values to HSV values.
Unfortunately, when the values are R=G=B, I'm getting a NaN, because of the 0/0 operation.
Do you know if there is an implemented method for this conversion in Java, or what do I have to do when I get the 0/0 division to get the right value of the HSV?
Here comes my method, adapted from some code on the Internet:
public static double[] RGBtoHSV(double r, double g, double b){
double h, s, v;
double min, max, delta;
min = Math.min(Math.min(r, g), b);
max = Math.max(Math.max(r, g), b);
// V
v = max;
delta = max - min;
// S
if( max != 0 )
s = delta / max;
else {
s = 0;
h = -1;
return new double[]{h,s,v};
}
// H
if( r == max )
h = ( g - b ) / delta; // between yellow & magenta
else if( g == max )
h = 2 + ( b - r ) / delta; // between cyan & yellow
else
h = 4 + ( r - g ) / delta; // between magenta & cyan
h *= 60; // degrees
if( h < 0 )
h += 360;
return new double[]{h,s,v};
}
I'm pretty sure what you want is RGBtoHSB
int r = ...
int g = ...
int b = ...
float[] hsv = new float[3];
Color.RGBtoHSB(r,g,b,hsv)
//hsv contains the desired values