I'm trying to implement averaging filter with different sizes 3x3 , 5x5 , 7x7 and 11x11 .. I did the calculations and the results are correct while debugging but the problem is that it is saved in the writable raster in negative, so I'm getting weird results. The second weird thing is that when I want to get the value of the same pixel that was saved in negative, it is retrieved with positive value !!
I'm using int.
What's wrong? any help ?!!
Here is my code for the 5x5 averaging filter.
public static BufferedImage filter5x5_2D(BufferedImage paddedBI , BufferedImage bi , double[][]filter)
{
WritableRaster myImage = paddedBI.copyData(null);
BufferedImage img = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
WritableRaster myImage2 = img.copyData(null);
for(int i =2; i< myImage.getHeight()-2; i++)
{
for(int j =2; j< myImage.getWidth()-2; j++)
{
int value = 0;
int copyi = i-2;
for (int m = 0 ; m<5 ; m++)
{
int copyj = j-2;
for (int n = 0; n<5; n++)
{
int result = myImage.getSample(copyj , copyi, 0);
double f = filter[m][n];
double add = result * filter[m][n];
value += (int) (filter[m][n] * myImage.getSample(copyj , copyi, 0));
copyj ++;
}
copyi++;
//myImage2.setSample(j-1 , i-1, 0, value);
}
myImage2.setSample(j-2 , i-2, 0, value);
//int checkResult = myImage2.getSample(j-1,i-1,0);
}
}
BufferedImage res= new BufferedImage(bi.getWidth(),bi.getHeight(),BufferedImage.TYPE_BYTE_GRAY);
res.setData(myImage2);
return res;
}
I do not find any negative values. Here is my main with what I have tested this code:
public static void main(String[] args) throws IOException {
BufferedImage bi = ImageIO.read(new File("C:/Tmp/test.bmp"));
BufferedImage newImage = new BufferedImage(bi.getWidth()+4, bi.getHeight()+4, bi.getType());
Graphics g = newImage.getGraphics();
g.setColor(Color.white);
g.fillRect(0,0,bi.getWidth()+4,bi.getHeight()+4);
g.drawImage(bi, 2, 2, null);
g.dispose();
double[][] filter = new double[5][5];
for( int i = 0; i < 5; ++i){
for( int j = 0; j < 5; ++j){
filter[i][j] = 1.0/(5*5);
}
}
BufferedImage filtered = filter5x5_2D(newImage, bi, filter);
ImageIO.write(filtered, "bmp", new File("C:/tmp/filtered.bmp"));
}
You should consider that your variables result, f and add are unused. Also it would be better if value would be of type double instead of int. In a worst case, you would get 25 times a value of 11 which will be rounded to zero after multiplying with 1/25. This would result in your code as a grey value of zero while it should result in 11.
I have a 3D array of booleans that represents some 3D terrain. Currently i can draw it by drawing a point at the position specified by its x y and z in the array, it looks like this.
What i can't figure out is how i would draw this using triangles, so it looks like actual terrain. I don't want to draw each on as a cube either.
Are there any algorithms to obtain which points to draw to (bear in mind that for the sake of efficiency only points on the exterior of a landmass should be drawn)?
Absolutely amazing question! I couldn't resist but to play with boxes, since boxes are sexy. It is actually fairly easy to produce boxes with the hidden faces omitted.
The following algorithm takes a list of 3D positions of true in your grid, which is easy to obtain by simply scanning through the grid and filling an array. Also with this data format you can store much larger grid, provided that the terrain is reasonably sparse. Up front, apologies for my spartan for-each loops, I just wanted to have the code in-place and avoid writing dozens of function objects or using lambdas. Also apologies for using C++ instead of Java, don't have javac at home and I'm not really good with it anyway. Here goes:
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <assert.h>
#include <math.h>
struct Pos3 {
int x, y, z;
Pos3(int _x = 0, int _y = 0, int _z = 0);
bool operator <(const Pos3 &other) const;
};
std::vector<int> index_buffer;
std::vector<float> vertex_buffer;
void onInitialize()
{
const int N = 32;
std::vector<Pos3> points;
GeneratePoints(points, N);
// input: bunch of points in NxNxN box (easy to get from a boolean array,
// can have much larger terrains if stored like this)
std::set<Pos3> point_set;
point_set.insert(points.begin(), points.end());
// put all the points to a set to be able to lookup neighbors (not needed with an array)
std::vector<std::vector<int> > polygons;
polygons.reserve(3 * points.size()); // guess
std::map<Pos3, int> vertex_map;
for(size_t i = 0, n = points.size(); i < n; ++ i) {
Pos3 p = points[i], corners[8] = {
p, Pos3(p.x + 1, p.y, p.z), Pos3(p.x + 1, p.y + 1, p.z), Pos3(p.x, p.y + 1, p.z),
Pos3(p.x, p.y, p.z + 1), Pos3(p.x + 1, p.y, p.z + 1), Pos3(p.x + 1, p.y + 1, p.z + 1),
Pos3(p.x, p.y + 1, p.z + 1)
};
// get corners of a cube
static const int sides[][3 + 4] = {
0, -1, 0, 4, 5, 1, 0, 1, 0, 0, 5, 6, 2, 1,
0, 1, 0, 6, 7, 3, 2, -1, 0, 0, 7, 4, 0, 3,
0, 0, -1, 0, 1, 2, 3, 0, 0, 1, 7, 6, 5, 4
};
// directions and side quad indices
for(int j = 0; j < 6; ++ j) {
Pos3 n(p.x + sides[j][0], p.y + sides[j][1], p.z + sides[j][2]); // position of a neighbor
if(point_set.find(n) != point_set.end())
continue; // have a neighbor, will not triangulate this side
polygons.resize(polygons.size() + 1);
std::vector<int> &poly = polygons.back(); // or use emplace_back() in c++11
poly.resize(4); // form quads
for(int v = 0; v < 4; ++ v) {
Pos3 vert = corners[sides[j][3 + v]];
std::map<Pos3, int>::iterator it; // use map to reuse vertices
if((it = vertex_map.find(vert)) == vertex_map.end())
vertex_map[vert] = poly[v] = vertex_map.size(); // new vertex
else
poly[v] = (*it).second; // existing vertex
}
}
// generate sides, skip invisible sides
// note that this still triangulates cavities, would have to flood-fill
// outside area and then set all that is not outside to opaque (did not
// solve that as this is also a valid behavior)
}
vertex_buffer.resize(vertex_map.size() * 3);
for(std::map<Pos3, int>::const_iterator it = vertex_map.begin(), e = vertex_map.end(); it != e; ++ it) {
size_t i = (*it).second * 3;
vertex_buffer[i + 0] = ((*it).first.x + .5f) / (N + 1) * 2 - 1;
vertex_buffer[i + 1] = ((*it).first.y + .5f) / (N + 1) * 2 - 1;
vertex_buffer[i + 2] = ((*it).first.z + .5f) / (N + 1) * 2 - 1;
}
// convert points from the discrete domain
// to a unit 3D cube centered around the origin
index_buffer.reserve(polygons.size() * 2 * 3); // approximate number of triangles
for(size_t i = 0, n = polygons.size(); i < n; ++ i) {
const std::vector<int> &poly = polygons[i];
for(size_t j = 2, n = poly.size(); j < n; ++ j) {
index_buffer.push_back(poly[0]);
index_buffer.push_back(poly[j]);
index_buffer.push_back(poly[j - 1]);
}
}
// convert polygons (those are actually quads) to triangles
}
There is also some more code that generates normals (ommited for the sake of clarity), the output looks like this:
The shape is a Julia set generated on a discrete lattice, you might recognize the shape when you turn it arround.
This is actually pretty similar to what you would get by the Delaunay triangulation if you could easily remove your interior points. The generated shape is hollow. There can be some "bubbles" in the shape, in case the booleans also contain a bubble (does not occur with Julia). This is easily fixed by flood-filling the booleans in order to fill those up.
Next, we can apply Catmull-Clark subdivision in order to get a smoother mesh:
typedef std::map<std::pair<int, int>, std::pair<size_t, int> > EdgeMap;
static bool Get_EdgeID(size_t &eid, int a, int b, EdgeMap &edges)
{
std::pair<int, int> e(std::min(a, b), std::max(a, b));
EdgeMap::iterator it = edges.find(e);
if(it == edges.end()) {
edges[e] = std::make_pair(eid = edges.size(), 1); // id, count
return true; // new edge
} else {
eid = (*it).second.first; // get id
++ (*it).second.second; // increase count
return false; // no new edge
}
}
void CatClark(std::vector<std::vector<int> > &src_quads, std::vector<float> &src_verts)
{
const static float vpw[4] = {9.0f, 3.0f, 1.0f, 3.0f};
const static float epw[4] = {3.0f, 3.0f, 1.0f, 1.0f};
std::vector<std::vector<int> > dst_quads(src_quads.size() * 4, std::vector<int>(4)); // will produce quads
std::vector<float> dst_verts(src_verts.size() + src_quads.size() * 3, 0); // alloc s¨pace for vertices
EdgeMap edges;
std::vector<int> face_valences(src_verts.size() / 3, 0);
const size_t off_vp = src_quads.size(), off_ep = off_vp + src_verts.size() / 3;
for(size_t j = 0; j < off_vp; ++ j) {
assert(src_quads[j].size() == 4); // otherwise won't work
size_t eid[4];
for(int k = 0; k < 4; ++ k) {
int quad[4];
for(int i = 0; i < 4; ++ i)
quad[i] = src_quads[j][(i + k) & 3]; // get the 4 vertices (but rotate them each k iteration)
if(Get_EdgeID(eid[k], quad[0], quad[1], edges)) // create edges
dst_verts.insert(dst_verts.end(), 3, .0f); // must add new vertex to accomodate subdivided edge point
++ face_valences[quad[0]]; // update face-valence
for(int n = 0; n < 3; ++ n)
dst_verts[j * 3 + n] += 0.25f * src_verts[quad[0] * 3 + n]; // increment face point
for(int i = 0; i < 4; ++ i) {
for(int n = 0; n < 3; ++ n) {
dst_verts[(off_vp + quad[0]) * 3 + n] += vpw[i] * src_verts[quad[i] * 3 + n]; // incremente vertex point
dst_verts[(off_ep + eid[k]) * 3 + n] += epw[i] * src_verts[quad[i] * 3 + n]; // increment edge point
}
}
}
for(int k = 0; k < 4; ++ k) { // make child faces
dst_quads[4 * j + k][0] = j;
dst_quads[4 * j + k][4] = off_ep + eid[(3 + k) & 3];
dst_quads[4 * j + k][5] = off_ep + eid[(0 + k) & 3];
dst_quads[4 * j + k][6] = off_vp + src_quads[j][k];
}
}
for(size_t j = 0, n = src_verts.size() / 3; j < n; ++ j) {
for(int n = 0; n < 3; ++ n)
dst_verts[(off_vp + j) * 3 + n] *= 0.0625f / float(face_valences[j]);
}
for(EdgeMap::const_iterator it = edges.begin(), e = edges.end(); it != e; ++ it) {
size_t j = (*it).second.first;
float rvalence = 0.1250f / float((*it).second.second);
for(int n = 0; n < 3; ++ n)
dst_verts[(off_ep + j) * 3 + n] *= rvalence;
}
dst_quads.swap(src_quads);
dst_verts.swap(src_verts);
}
This algorithm was adapted to work with STL containers from Iñigo 'iq' Quilez / rgba, "Tricks and techniques for rgba's past and future intros", Breakpoint, 2007.
This gives output quite similar to what you would get with marching cubes / marching tetrahedrons / marching triangles, except that it is always higher resolution than that of the original lattice (with the above methods you can easily change the triangulation resolution). A slightly different view of the same data:
Or without wireframe:
The complete source code, along with Visual Studio workspace and win32 binaries can be found at here. It uses GLUT and the old fixed-function pipeline to display the generated geometry (only for simplicity and portability, otherwise I'd have to include GLEW or the like). I really enjoyed toying around with your question, I hope you will like the output ...
If you want to use marching cubes, you can find many demos online, or check out this real-time water simulation I did a couple years ago.
If you have the points describing the outer shell of your terrain, this package is VERY good (fast) for calculating the Delaunay Triangulation of that set of points:
http://www.cs.bgu.ac.il/~benmoshe/DT/
You can later draw each of the triangles from the triangulation. I made a couple or methods for converting everything back to doubles for use with JOGL that you might find helpful:
public static ArrayList<Point_dt[]> DTtoTriListDT(Delaunay_Triangulation DT){
ArrayList<Point_dt[]> triangles = new ArrayList<Point_dt[]>();
Point_dt[] triangle = new Point_dt[3];
Iterator<Triangle_dt> surface = DT.trianglesIterator();
while(surface.hasNext()){
Triangle_dt tri = surface.next();
triangle[0] = tri.p1();
triangle[1] = tri.p2();
triangle[2] = tri.p3();
triangles.add(triangle);
}
return triangles;}
and
public static ArrayList<double[][]> DTtoTriList(Delaunay_Triangulation DT){
ArrayList<Point_dt[]> trianglesdt = Algebra.DTtoTriListDT(DT);
ArrayList<double[][]> triangles = new ArrayList<double[][]>();
double[][] triangle = new double[3][3];
Iterator<Point_dt[]> surface = trianglesdt.iterator();
while(surface.hasNext()){
Point_dt[] tri = surface.next();
triangle[0][0] = tri[0].x();
triangle[0][1] = tri[0].y();
triangle[0][2] = tri[0].z();
triangle[1][0] = tri[1].x();
triangle[1][1] = tri[1].y();
triangle[1][2] = tri[1].z();
triangle[2][0] = tri[2].x();
triangle[2][1] = tri[2].y();
triangle[2][2] = tri[2].z();
triangles.add(triangle);
}
return triangles;
}
I have it all in an Algebra class (FYI).
With the last method, you get an ArrayList with tree sets of three doubles on each entry (each set contains the three coordinates of each point and each entry is one triangle).
I have a situation where I need to invert the alpha channel of a VolatileImage
My current implementation is the obvious, but very slow;
public BufferedImage invertImage(VolatileImage v) {
BufferedImage b = new BufferedImage(v.getWidth(), v.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics g = b.getGraphics();
g.drawImage(v, 0, 0, null);
for(int i = 0; i < b.getWidth(); i++) {
for(int(j = 0; j < b.getHeight(); j++) {
Color c = new Color(b.getRGB(i, j, true));
c = new Color(c.getRed(), c.getGreen(), c.getBlue(), 255 - c.getAlpha());
b.setRGB(i, j, c.getRGB());
}
}
return b;
}
This works fine, but is painfully slow. I have large images and need this to be fast. I have messed around with the AlphaComposite but to no avail - this is not really a composting problem as far as I understand.
Given that 255 - x is equivalent to x & 0xff for 0 <= x < 256, can I not do an en-masse XOR over the alpha channel somehow?
After a lot of googleing, I came across DataBuffer classes being used as maps into BufferedImages:
DataBufferByte buf = (DataBufferByte)b.getRaster().getDataBuffer();
byte[] values = buf.getData();
for(int i = 0; i < values.length; i += 4) values[i] = (byte)(values[i] ^ 0xff);
This inverts the values of the BufferedImage (you do not need to draw it back over, altering the array values alters the buffered image itself).
My tests show this method is about 20 times faster than jazzbassrob's improvement, which was about 1.5 times faster than my original method.
You should be able to speed it up by avoiding all the getters and the constructor inside the loop:
for(int i = 0; i < b.getWidth(); i++) {
for(int(j = 0; j < b.getHeight(); j++) {
b.setRGB(b.getRGB(i, j) ^ 0xFF000000);
}
}
I have this code:
{
Robot robot = new Robot();
Color inputColor = new Color();
Rectangle rectangle = new Rectangle(0, 0, 1365, 770);
BufferedImage image = robot.createScreenCapture(rectangle);
for(int x = 0; x < rectangle.getWidth(); x++)
{
for (int y = 0; y < rectangle.getHeight(); y++)
{
if (image.getRGB(x, y) == inputColor.getRGB())
{
return 1;
break;
}
}
}
}
it is supposed to, and does, take a screenshot and find in it a pixel specified by the inputColor. However the program requirements have changed, and now it needs to find a string of pixels 5 long that match a given string. Is there an easy way to specify this with the existing code, or will I need to change it? I mean, can I keep the existing code and define inputColor as a string with the values of the 5 pixels, or do I need to change the whole algorithm?
I think something like this would work. Not the best efficiency, but its a bone to chew.
int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth())) {
for (int i = 0; i < pixels.length; i++) {
if (Array.equals(search, Array.copyOfRange(pixels, i, i + search.length)) {
//found it
}
}
search would be an array of integers(your colors).
is it possible to loop through bitmap and set each color value to an array? at the moment only top row of array is getting written to dst bitmap. eg
.
Bitmap dst = Bitmap.createBitmap(width, height,input.getConfig() ); //output pic
int origPixel = 0;
int []arr = new int[input.getWidth()*input.getHeight()];
int color = 0;
for(int j=0;j<dst.getHeight();j++){
for(int i=0;i<dst.getWidth();i++){
origPixel= input.getPixel(i,j);
color = ........do something special with that pixel transform it whatever
if( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) <= 22500 ){
arr[i]=color;
}else{
arr[i]=origPixel;
}
}
}
Bitmap dst2 = Bitmap.createBitmap(arr,width,height,input.getConfig());
return dst2;
you need to update arr[k] where k initialize before first loop and increment in the second loop see the modified code a hunk of your code:
int k =0;
for(int j=0;j<dst.getHeight();j++){
for(int i=0;i<dst.getWidth();i++, k++){
origPixel= input.getPixel(i,j);
color = ........do something special with that pixel transform it whatever
if( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) <= 22500 ){
arr[k]=color;
}else{
arr[k]=origPixel;
}
you are overriding values in array.