I need to create a new, smaller, image from a larger image at runtime. The smaller image size is fixed (square) and represents a specific region of the larger image (the smaller image is a subset of the larger image). Image format doesn't matter.
Thanks.
You can use this function:
Bitmap[] splitImage(Bitmap bitmap, int rCnt, int cCnt) {
Bitmap[] result = new Bitmap[rCnt * cCnt];
int w = bitmap.getWidth() / cCnt;
int h = bitmap.getHeight() / rCnt;
for (int i = 0; i < rCnt; i++)
for (int j = 0; j < cCnt; j++) {
Bitmap bitmapPart = new Bitmap(w, h);
Graphics g = new Graphics(bitmapPart);
g.drawBitmap(0, 0, w, h, bitmap, w * j, h * i);
result[i * cCnt + j] = bitmapPart;
}
return result;
}
Take a look at full source of Puzzle game for BB on Google Code
Related
I am trying to modelize a physical problem of photoelasticity on a surface. I succeed to get an array of X,Y - coordinates of the surface and for each points I have a corresponding color in a RGB format. I used Python scatter to plot and the result is already great but there is still some discontinuities because of the lack of resolution that I can not improve :( I just wanted to ask how I can generate the same surface plot in a continuous way (with new "in-between" points for which the color of them have been interpolated with respect to the neighborhood points). I am not necessarily looking for coding it in python, every software is welcome. Thanks!
I wrote this in javascript: https://jsfiddle.net/87nw05kz/
The important part is calculateColor. It finds the inverse square of the distance to each color from the pixel being shaded and it uses that to decide how much that pixel should be effected by each color.
function calculateColor(x, y) {
let total = 0;
for (let i = 0; i < colors.length; i++) {
let c = colors[i];
let d = distance(c.x, c.y, x, y);
if (d === 0) {
return c;
}
d = 1 / (d * d);
c.d = d;
total += d;
}
let r = 0, g = 0, b = 0;
for (let i = 0; i < colors.length; i++) {
let c = colors[i];
let ratio = c.d / total;
r += ratio * c.r;
g += ratio * c.g;
b += ratio * c.b;
}
r = Math.floor(r);
g = Math.floor(g);
b = Math.floor(b);
return {r:r,g:g,b:b};
}
I have a virtual scanner that generates a 2.5-D view of a point cloud (i.e. a 2D-projection of a 3D point cloud) depending on camera position. I'm using the vtkCamera.GetProjectionTransformMatrix() to get transformation matrix from world/global to camera coordinates.
However, if the input point cloud has color information for points I would like to preserve it.
Here are the relevant lines:
boost::shared_ptr<pcl::visualization::PCLVisualizer> vis; // camera location, viewpoint and up direction for vis were already defined before
vtkSmartPointer<vtkRendererCollection> rens = vis->getRendererCollection();
vtkSmartPointer<vtkRenderWindow> win = vis->getRenderWindow();
win->SetSize(xres, yres); // xres and yres are predefined resolutions
win->Render();
float dwidth = 2.0f / float(xres),
dheight = 2.0f / float(yres);
float *depth = new float[xres * yres];
win->GetZbufferData(0, 0, xres - 1, yres - 1, &(depth[0]));
vtkRenderer *ren = rens->GetFirstRenderer();
vtkCamera *camera = ren->GetActiveCamera();
vtkSmartPointer<vtkMatrix4x4> projection_transform = camera->GetProjectionTransformMatrix(ren->GetTiledAspectRatio(), 0, 1);
Eigen::Matrix4f mat1;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
mat1(i, j) = static_cast<float> (projection_transform->Element[i][j]);
mat1 = mat1.inverse().eval();
Now, mat1 is used to transform coordinates to camera-view:
pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud;
int ptr = 0;
for (int y = 0; y < yres; ++y)
{
for (int x = 0; x < xres; ++x, ++ptr)
{
pcl::PointXYZ &pt = (*cloud)[ptr];
if (depth[ptr] == 1.0)
{
pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
continue;
}
Eigen::Vector4f world_coords(dwidth * float(x) - 1.0f,
dheight * float(y) - 1.0f,
depth[ptr],
1.0f);
world_coords = mat1 * world_coords;
float w3 = 1.0f / world_coords[3];
world_coords[0] *= w3;
world_coords[1] *= w3;
world_coords[2] *= w3;
pt.x = static_cast<float> (world_coords[0]);
pt.y = static_cast<float> (world_coords[1]);
pt.z = static_cast<float> (world_coords[2]);
}
}
I want the virtual scanner to return pcl::PointXYZRGB point cloud with color information.
Any help on how to implement this from someone experienced in VTK would save some of my time.
It's possible that I missed a relevant question already asked here - in that case, please point me to it. Thanks.
If I understand correctly that you want to get the color in which the point was rendered into the win RenderWindow, you should be able to get the data from the rendering buffer by calling
float* pixels = win->GetRGBAPixelData(0, 0, xres - 1, yres - 1, 0/1).
This should give you each pixel of the rendering buffer as an array in the format [R0, G0, B0, A0, R1, G1, B1, A1, R2....]. The last parameter which I wrote as 0/1 is whether the data should be taken from front or back opengl buffers. I presume by default double buffering should be on, so then you want to read from back buffer (use '1'), but I am not sure.
Once you have that, you can get the color in your second loop for all pixels that belong to points (depth[ptr] != 1.0) as:
pt.R = pixels[4*ptr];
pt.G = pixels[4*ptr + 1];
pt.B = pixels[4*ptr + 2];
You should call win->ReleaseRGBAPixelData(pixels) once you're done with it.
https://stackoverflow.com/a/2574798/159072
public static Bitmap BitmapTo1Bpp(Bitmap img)
{
int w = img.Width;
int h = img.Height;
//
Bitmap bmp = new Bitmap(w, h, PixelFormat.Format1bppIndexed);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
Why this addition and division?
byte[] scan = new byte[(w + 7) / 8];
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{////Why this condition check?
if (x % 8 == 0)
//Why divide by 8?
scan[x / 8] = 0;
Color c = img.GetPixel(x, y);
//Why this condition check?
if (c.GetBrightness() >= 0.5)
{
// What is going on here?
scan[x / 8] |= (byte)(0x80 >> (x % 8));
}
}
// Why Martial.Copy() called here?
Marshal.Copy(scan, 0, (IntPtr)((long)data.Scan0 + data.Stride * y), scan.Length);
}
bmp.UnlockBits(data);
return bmp;
}
The code uses some basic bit-hacking techniques, required because it needs to set bits and the minimum storage element you can address in C# is a byte. I intentionally avoided using the BitArray class.
int w = img.Width;
I copy the Width and Height properties of the bitmap into a local variable to speed up the code, the properties are too expensive. Keep in mind that w are the number of pixels across the bitmap, it represents the number of bits in the final image.
byte[] scan = new byte[(w + 7) / 8];
The scan variable stores the pixels in one scan line of the bitmap. The 1bpp format uses 1 bit per pixel so the total number of bytes in a scan line is w / 8. I add 7 to ensure the value is rounded up, necessary because integer division always truncates. w = 1..7 requires 1 byte, w = 8..15 requires 2 bytes, etcetera.
if (x % 8 == 0) scan[x / 8] = 0;
The x % 8 expression represents the bit number, x / 8 is the byte number. This code sets all the pixels to Black when it progresses to the next byte in the scan line. Another way to do it would be re-allocating the byte[] in the outer loop or resetting it back to 0 with a for-loop.
if (c.GetBrightness() >= 0.5)
The pixel should be set to White when the source pixel is bright enough. Otherwise it leaves it at Black. Using Color.Brightness is a simple way to avoid dealing with the human eye's non-linear perception of brightness (luminance ~= 0.299 * red + 0.587 * green + 0.114 * blue).
scan[x / 8] |= (byte)(0x80 >> (x % 8));
Sets a bit to White in the scan line. As noted x % 8 is the bit number, it shifts 0x80 to the right by the bit number, they are stored in reverse order in this pixel format.
So I'm writing up a processing sketch to test a randomized terrain generator for a scorched earth clone I'm working on. It seems to work as intended but with one minor problem. In the code I generate 800 1 pixel wide rectangles and set the fill to brown beforehand. The combination of the rectangles should be a solid mass with a brown dirt-like color (77,0,0).
However, the combination shows up as black regardless of the rgb fill value set. I think it might have something to do with each rectangle's border being black? Does anyone know what is happening here offhand?
final int w = 800;
final int h = 480;
void setup() {
size(w, h);
fill(0,128,255);
rect(0,0,w,h);
int t[] = terrain(w,h);
fill(77,0,0);
for(int i=0; i < w; i++){
rect(i, h, 1, -1*t[i]);
}
}
void draw() {
}
int[] terrain(int w, int h){
width = w;
height = h;
//min and max bracket the freq's of the sin/cos series
//The higher the max the hillier the environment
int min = 1, max = 6;
//allocating horizon for screen width
int[] horizon = new int[width];
double[] skyline = new double[width];
//ratio of amplitude of screen height to landscape variation
double r = (int) 2.0/5.0;
//number of terms to be used in sine/cosine series
int n = 4;
int[] f = new int[n*2];
//calculating omegas for sine series
for(int i = 0; i < n*2 ; i ++){
f[i] = (int) random(max - min + 1) + min;
}
//amp is the amplitude of the series
int amp = (int) (r*height);
for(int i = 0 ; i < width; i ++){
skyline[i] = 0;
for(int j = 0; j < n; j++){
skyline[i] += ( sin( (f[j]*PI*i/height) ) + cos(f[j+n]*PI*i/height) );
}
skyline[i] *= amp/(n*2);
skyline[i] += (height/2);
skyline[i] = (int)skyline[i];
horizon[i] = (int)skyline[i];
}
return horizon;
}
I think it might have something to do with each rectangle's border being black?
I believe this is the case. In your setup() function, I added the noStroke() function before you draw the rectangles. This removes the black outline to the rectangles. Since each rectangle is only 1 pixel wide, having this black stroke (which is on by default) makes the color of each rectangle black, no matter what color you try to choose before.
Here is an updated setup() function - I now see a reddish brown terrain:
void setup() {
size(w, h);
fill(0, 128, 255);
rect(0, 0, w, h);
int t[] = terrain(w, h);
fill(77, 0, 0);
noStroke(); // here
for (int i=0; i < w; i++) {
rect(i, h, 1, -1*t[i]);
}
}
I need to process the first "Original" image to get something similar to the second "Enhanced" one. I applied some naif calculation and the new image has more contrast and more strong colors but in the higher color regions a color hole appears. I have no idea about image processing, it would be great if you can suggest me which concepts and/or algorithms I could apply to get the result without this problem.
Convert the image to the HSB (Hue, Saturation, Brightness) color space.
Multiply the saturation by some amount. Use a cutoff value if your platform requires it.
Example in Mathematica:
satMult = 4; (*saturation multiplier *)
imgHSB = ColorConvert[Import["http://i.imgur.com/8XkxR.jpg"], "HSB"];
cs = ColorSeparate[imgHSB]; (* separate in H, S and B*)
newSat = Image[ImageData[cs[[2]]] * satMult]; (* cs[[2]] is the saturation*)
ColorCombine[{cs[[1]], newSat, cs[[3]]}, "HSB"]] (* rebuild the image *)
A table increasing the saturation value:
The "holes" that you see in the processed picture are the darker areas of the original picture, which went to negative values with your darkening algorithm. I suspect these out of range values are then written to the new image as positive numbers, so they end up in the higher part of the brightness scale. For example, let's say a pixel value is 10, and you are substracting 12 from all pixels to darken them a bit. This pixel will underflow and become -2. When you write it back to the file, -2 gets represented as 0xfe in hex, and this is 254 if you take it as an unsigned number.
You should use an algorithm that keeps the pixel values within the valid range, or at least you should "clamp" the values to the valid range. A typical clamp function defined as a C macro would be:
#define clamp(p) (p < 0 ? 0 : (p > 255 ? 255 : p))
If you add the above macro to your processing function it will take care of the "holes", but instead you will now have dark colors in those places.
If you are ready for something a bit more advanced, here on Wikipedia they have the brightness and contrast formulas that are used by The GIMP. These which will do a pretty good job with your image if you choose the proper coefficients.
This wikipedia article does a good job of explaining histogram equalization for contrast enhancement.
Code for grayscale images:
unsigned char* EnhanceContrast(unsigned char* data, int width, int height)
{
int* cdf = (int*) calloc(256, sizeof(int));
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
int val = data[width*y + x];
cdf[val]++;
}
}
int cdf_min = cdf[0];
for(int i = 1; i < 256; i++) {
cdf[i] += cdf[i-1];
if(cdf[i] < cdf_min) {
cdf_min = cdf[i];
}
}
unsigned char* enhanced_data = (unsigned char*) malloc(width*height);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
enhanced_data[width*y + x] = (int) round(cdf[data[width*y + x]] - cdf_min)*255.0/(width*height-cdf_min);
}
}
free(cdf);
return enhanced_data;
}