I was trying to realize an actually simple action, namely to change the color of a normal bitmap.
Unfortunately, there appeared a few errors. In my case I want a bitmap of grey steel to turn into redder steel. Therefore, I wrote some code, which gets the color int of each pixel and raises the red value for each one. Now two things happen:
Firstly, it really takes a long, long time to convert all the pixels, even if I use an AsyncTask.
Secondly, when it finishes one cycle, the whole bitmap kind of rotates and multiplies like in the picture below.
Is there any way to smoothly realize my aim? The thing is that I often see this action in other apps without having problems, so the must be a way to reach my goal.
Thank you!
PS: Please do not be irritated by the comments, they are just tries to find another way!
"steel image" https://drive.google.com/file/d/0B72QIg-baxzjakJsQkFRZFVFOFU/edit?usp=sharing
public void adjustColor(Bitmap bmp)
{
/*for(int i=0; i<bmp.getHeight()-1; i++) {
for(int j=0; j<bmp.getWidth()-1; j++) {
if(bmp.getPixel(j, i) != Color.TRANSPARENT) {
if(Color.green(bmp.getPixel(j, i)) <= 175 && Color.green(bmp.getPixel(j, i)) >= 65) {
red = Color.red(bmp.getPixel(j, i));
green = Color.green(bmp.getPixel(j, i));
blue = Color.blue(bmp.getPixel(j, i));
if (i == bmp.getHeight()-1) {
red = Color.red(bmp.getPixel(j, bmp.getHeight()));
green = Color.green(bmp.getPixel(j, bmp.getHeight()));
blue = Color.blue(bmp.getPixel(j, bmp.getHeight()));}
if ((red + mOfen.heatQ/10) <= 205) red = red + mOfen.heatQ/10;
bmp.setPixel(j, i, Color.rgb(red, green, blue));
}}
}
}*/
for(int h=0; h<bmp.getWidth()*bmp.getHeight(); h++) {
int x = h-bmp.getWidth()*(((int)h/bmp.getWidth()+1)-1);
int y = h/bmp.getWidth();
Log.d("roh", "y " + Integer.toString(y));
Log.d("roh", "height " + Integer.toString(bmp.getHeight()));
if(Color.green(bmp.getPixel(x, y)) <= 175 && Color.green(bmp.getPixel(x, y)) >= 65) {
bmp.setPixel(x, y, Color.WHITE);
red = Color.red( allpixels[h] );
green = Color.green( allpixels[h] );
blue = Color.blue( allpixels[h] );
/* for(int n=1; n<=10; n++) {
/*Log.d("roh", "left " + Float.toString(mOfen.rRoh[n-1].left));
Log.d("roh", "right " + Float.toString(mOfen.rRoh[n-1].right));
Log.d("roh", "n " + Integer.toString(n));
Log.d("roh", "x+RohX " + Float.toString(x+RohX));
Log.d("roh", "top " + Float.toString(mOfen.rRoh[n-1].top));
Log.d("roh", "bottom " + Float.toString(mOfen.rRoh[n-1].bottom));
Log.d("roh", "n " + Integer.toString(n));
Log.d("roh", "y+RohY " + Float.toString(y+RohY)); */
/* if( mOfen.rRoh[n-1].left < x+RohX && y+RohY > mOfen.rRoh[n-1].top &&
mOfen.rRoh[n-1].right > x+RohX && y+RohY < mOfen.rRoh[n-1].bottom) {
/*if ((mOfen.heat[n-1]) <= 245 && (mOfen.heat[n-1]) > red ) red = mOfen.heat[n-1]; */ if(red<255) red++;
/* Log.d("red", "red" + Integer.toString(red));
Log.d("red", Float.toString(x+mOfen.rRoh[n-1].left));
Log.d("red", Float.toString((mOfen.rRoh[n-1].left)));
}} */
allpixels[h] = Color.rgb(red, green, blue);
}
}
copyArrayIntoBitmap(bmp);
//bmp.setPixels(allpixels, 0, bmp.getWidth(), 0, 0, bmp.getWidth(), bmp.getHeight());
}
public void copyBitmapIntoArray(Bitmap bmp)
{
allpixels = new int[bmp.getWidth()*bmp.getHeight()];
int count = 0;
for(int i=0; i<bmp.getHeight()-1; i++) {
for(int j=0; j<bmp.getWidth()-1; j++) {
allpixels[count] = bmp.getPixel(j, i);
count++;
}
}
}
public void copyArrayIntoBitmap(Bitmap bmp)
{
int count = 0;
for(int i=0; i<bmp.getHeight()-1; i++) {
for(int j=0; j<bmp.getWidth()-1; j++) {
bmp.setPixel(j, i, allpixels[count]);
count++;
}
}
}
So your code and your question have different operations being said. Looks like you are doing a little more than just globally updating all pixels to be a bit more red. I say this because both code in your question, commented and uncommented, have a conditional part in them that determines how much more red to make a pixel. I also assume this is why a simple LightingColorFilter will not work, since you need to choose which pixels are affected.
Some issues I spotted immediately:
I am betting you are running into a lot of I/O issues with regards to all the memory allocation and memory copying in this code. WxH is your number of pixels, obviously. But that is also a fairly large amount of entites to do an operation on. So your calls to getPixel() and setPixel() iteratively are very very slow already and doing this for each pixel is just impractical. You should use bulk getPixels() and setPixels() if you are going to do it this way. Just this alone should speed up a large chunk of your process.
Now if you want a forward compatible performance boost (like one that scales better with better hardware), you could look into RenderScript This allows you to do work on a per pixel level, but across multiple CPU's and GPU's. It's sort of like a map-reduce framework for your image buffers. You will have to write some C, but if you find this component to be used a lot then this will probably help out quite a bit and be pretty snappy (especially for larger images).
Try to use LightingColorFilter, some examples are here:
LightingColorFilter example or how to use the LightingColorFilter to make the image form dark to light
Related
game.batch.begin();
for (Array obstacle_array123: obstacle_array) {
body = obstacle_array123;
for (Body bodies: body) {
if (bodies.getUserData() instanceof Array && bodies.isActive()) {
sprites_array = (Array)bodies.getUserData();
for (int fix_pos = 0; fix_pos < sprites_array.size; fix_pos++) {
sprite = sprites_array.get(fix_pos);
if (verts.size != 0) verts.removeRange(0, verts.size - 1);
f = bodies.getFixtureList().get(fix_pos);
s = (PolygonShape)f.getShape();
transform = bodies.getTransform();
for (int i = 0; i < s.getVertexCount(); i++)
{
s.getVertex(i, tmp);
transform.mul(tmp);
verts.add(new Vector2(tmp));
}
rotation_point.set((verts.get(0).x + verts.get(1).x + verts.get(2).x + verts.get(3).x) / 4, (verts.get(0).y + verts.get(1).y + verts.get(2).y + verts.get(3).y) / 4);
sprite.setPosition(rotation_point.x - sprite.getWidth() / 2, rotation_point.y - sprite.getHeight() / 2);
sprite.setRotation(bodies.getAngle() * MathUtils.radiansToDegrees);
sprite.draw(game.batch);
}
}
}
}
game.batch.end();
I have a game where my bodies are made from multiple square fixtures, so this is the code to render each square sprite on each square fixture.
2 problems - 1.st --> it only renders the first sprite in the array
2.nd --> if you look at the following loop (SOLVED)
for (int i = 0; i < s.getVertexCount(); i++)
{
s.getVertex(i, tmp);
transform.mul(tmp);
verts.add(new Vector2(tmp));
}
well it is apperantly different compared to
for (int i = 0; i < s.getVertexCount(); i++)
{
s.getVertex(i, tmp);
transform.mul(tmp);
verts.add(tmp);
}
The spawned coordinates in 2nd example are wrong for half width and half height of the square.
When I try to get the coordinated from both examples the numbers are the same, but when setting the sprite position, 2nd example goes off.
You should probably ask both questions separately, but to answer your second question, then they ARE different.
In the first one you add a new Vector2 to verts each time through the loop. So verts will end up holding a load of different Vector2's.
In the second one you add the same Vector2 to verts over and over again, so it will just have one Vector2 with the same value over and over again (remember Java is pass by reference).
Caveat - My answer assumes that verts is some sort of standard collection or a libgdx Array.
I'm using a for loop to implement the loading and handling of Sprite objects for display for a keyboard for a game of hangman. The loop makes it through to the 4th iteration and crashes. The error it gives me says:
Texture must not exceed the bounds of the atlas
This should actually work as all the images are 64x64 and the atlas is declared as such:
this.mAtlas[i] = new BitmapTextureAtlas(this.getTextureManager(),256, 256,TextureOptions.BILINEAR);
I'm using an array of atlases and an array of textures in which to load the images and the I load the atlas. After that I'm then passing the texture into a custom class that implements sprite. And finally I attach the loaded sprite into the scene. Here is the whole code for the loop:
for(int i = 0; i < 28; i++)
{
String name = Integer.toString(i);
name+= ".png";
this.mAtlas[i] = new BitmapTextureAtlas(this.getTextureManager(),256, 256,TextureOptions.BILINEAR);
this.mTexture[i] = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mAtlas[i], this, name, (i*64) + 5,0);
this.mAtlas[i].load();
if(i % 13 == 0)
{
yPos -= 64;
}
if(i < 26)
{
letterPass = alphabet.substring(i);
}
else if(i == 26)
{
letterPass = "BackSpace";
}
else if(i == 27)
{
letterPass = "return";
}
letters[i] = new Letter((i * 64)+ 5.0f, yPos, this.mTexture[i].getHeight(), this.mTexture[i].getHeight(), this.mTexture[i], this.mEngine.getVertexBufferObjectManager());
letters[i].setLetter(letterPass);
mScene.attachChild(letters[i]);
}
The line where the crash occurs is:
this.mTexture[i] = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mAtlas[i], this, name, (i*64) + 5,0);
I cannot seem to figure out why it's crashing and I'd appreciate any help
You texture atlas is 256x256 pixels large. Your sprites are 64x64 pixels and you create an atlas for each of them... That means you are wasting a lot of space. And it doesn't even work because on this line:
this.mTexture[i] = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mAtlas[i], this, name, (i*64) + 5,0);
You are placing the texture onto atlas at position [i * 64 + 5, 0]. I bet it fails on 4th texture. 3 * 64 + 5 +64 = 261, you are out of bounds.
I want to ask about some ideas / study materials connected to binarization. I am trying to create system that detects human emotions. I am able to get areas such as brows, eyes, nose, mouth etc. but then comes another stage -> processing...
My images are taken in various places/time of day/weather conditions. It's problematic during binarization, with the same treshold value one images are fully black, other looks well and provide me informations I want.
What I want to ask you about is:
1) If there is known way how to bring all images to the same level of brightness?
2) How to create dependency between treshold value and brightness on image?
What I have tried for now is normalize the image... but there are no effects, maybe I'm doing something wrong. I'm using OpenCV (for android)
Core.normalize(cleanFaceMatGRAY, cleanFaceMatGRAY,0, 255, Core.NORM_MINMAX, CvType.CV_8U);
EDIT:
I tried adaptive treshold, OTSU - they didnt work for me. I have problems with using CLAHE in Android but I managed to implement Niblack algorithm.
Core.normalize(cleanFaceMatGRAY, cleanFaceMatGRAY,0, 255, Core.NORM_MINMAX, CvType.CV_8U);
nibelBlackTresholding(cleanFaceMatGRAY, -0.2);
private void nibelBlackTresholding(Mat image, double parameter) {
Mat meanPowered = image.clone();
Core.multiply(image, image, meanPowered);
Scalar mean = Core.mean(image);
Scalar stdmean = Core.mean(meanPowered);
double tresholdValue = mean.val[0] + parameter * stdmean.val[0];
int totalRows = image.rows();
int totalCols = image.cols();
for (int cols=0; cols < totalCols; cols++) {
for (int rows=0; rows < totalRows; rows++) {
if (image.get(rows, cols)[0] > tresholdValue) {
image.put(rows, cols, 255);
} else {
image.put(rows, cols, 0);
}
}
}
}
The results are really good, but still not enough for some images. I paste links cuz images are big and I don't want to take too much screen:
For example this one is tresholded really fine:
https://dl.dropboxusercontent.com/u/108321090/a1.png
https://dl.dropboxusercontent.com/u/108321090/a.png
But bad light produce shadows sometimes and this gives this effect:
https://dl.dropboxusercontent.com/u/108321090/b1.png
https://dl.dropboxusercontent.com/u/108321090/b.png
Do you have any idea that could help me to improve treshold of those images with high light difference (shadows)?
EDIT2:
I found that my previous Algorithm is implemented in wrong way. Std was calculated in wrong way. In Niblack Thresholding mean is local value not global. I repaired it according to this reference http://arxiv.org/ftp/arxiv/papers/1201/1201.5227.pdf
private void niblackThresholding2(Mat image, double parameter, int window) {
int totalRows = image.rows();
int totalCols = image.cols();
int offset = (window-1)/2;
double tresholdValue = 0;
double localMean = 0;
double meanDeviation = 0;
for (int y=offset+1; y<totalCols-offset; y++) {
for (int x=offset+1; x<totalRows-offset; x++) {
localMean = calculateLocalMean(x, y, image, window);
meanDeviation = image.get(y, x)[0] - localMean;
tresholdValue = localMean*(1 + parameter * ( (meanDeviation/(1 - meanDeviation)) - 1 ));
Log.d("QWERTY","TRESHOLD " +tresholdValue);
if (image.get(y, x)[0] > tresholdValue) {
image.put(y, x, 255);
} else {
image.put(y, x, 0);
}
}
}
}
private double calculateLocalMean(int x, int y, Mat image, int window) {
int offset = (window-1)/2;
Mat tempMat;
Rect tempRect = new Rect();
Point leftTop, bottomRight;
leftTop = new Point(x - (offset + 1), y - (offset + 1));
bottomRight = new Point(x + offset, y + offset);
tempRect = new Rect(leftTop, bottomRight);
tempMat = new Mat(image, tempRect);
return Core.mean(tempMat).val[0];
}
Results for 7x7 window and proposed in reference k parameter = 0.34: I still can't get rid of shadow on faces.
https://dl.dropboxusercontent.com/u/108321090/b2.png
https://dl.dropboxusercontent.com/u/108321090/b1.png
things to look at:
http://docs.opencv.org/java/org/opencv/imgproc/CLAHE.html
http://docs.opencv.org/java/org/opencv/imgproc/Imgproc.html#adaptiveThreshold(org.opencv.core.Mat,%20org.opencv.core.Mat,%20double,%20int,%20int,%20int,%20double)
http://docs.opencv.org/java/org/opencv/imgproc/Imgproc.html#threshold(org.opencv.core.Mat,%20org.opencv.core.Mat,%20double,%20double,%20int) (THRESH_OTSU)
I'm a beginner in openCV4android and I would like to get some help if possible
.
I'm trying to detect colored triangles,squares or circles using my Android phone camera but I don't know where to start.
I have been reading OReilly Learning OpenCV book and I got some knowledge about OpenCV.
Here is what I want to make:
1- Get the tracking color (just the color HSV) of the object by touching the screen
- I have already done this by using the color blob example from the OpenCV4android example
2- Find on the camera shapes like triangles, squares or circles based on the color choosed before.
I have just found examples of finding shapes within an image. What I would like to make is finding using the camera on real time.
Any help would be appreciated.
Best regards and have a nice day.
If you plan to implement NDK for your opencv stuff then you can use the same idea they are using in OpenCV tutorial 2-Mixedprocessing.
// on camera frames call your native method
public Mat onCameraFrame(CvCameraViewFrame inputFrame)
{
mRgba = inputFrame.rgba();
Nativecleshpdetect(mRgba.getNativeObjAddr()); // native method call to perform color and object detection
// the method getNativeObjAddr gets the address of the Mat object(camera frame) and passes it to native side as long object so that you dont have to create and destroy Mat object on each frame
}
public native void Nativecleshpdetect(long matAddrRgba);
In Native side
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_Nativecleshpdetect(JNIEnv*, jobject,jlong addrRgba1)
{
Mat& mRgb1 = *(Mat*)addrRgba1;
// mRgb1 is a mat object which points to the address of the input camera frame, so all the manipulations you do here will reflect on the live camera frame
//once you have your mat object(i.e mRgb1 ) you can implement all the colour and shape detection algorithm you have learnt in opencv book
}
since all manipulations are done using pointers you have to be bit careful handling them. hope this helps
Why dont you make use of JavaCV i think its a better alternative..you dont have to use the NDK at all for this..
try this:
http://code.google.com/p/javacv/
If you check OpenCV's Back Projection tutorial it does what you are looking for (and a bit more).
Back Projection:
"In terms of statistics, the values stored in the BackProjection
matrix represent the probability that a pixel in a image belongs to
the region with the selected color."
I have converted that tutorial to OpenCV4Android (2.4.8) like you were looking for, it does not use Android NDK. You can see all the code here at Github.
You can also check this answer for more details.
Though its a bit late i would like to make a contribution to the question.
1- Get the tracking color (just the color HSV) of the object by
touching the screen - I have already done this by using the color blob
example from the OpenCV4android example
Implement OnTouchListener to your activity
onTouch function
int cols = mRgba.cols();
int rows = mRgba.rows();
int xOffset = (mOpenCvCameraView.getWidth() - cols) / 2;
int yOffset = (mOpenCvCameraView.getHeight() - rows) / 2;
int x = (int) event.getX() - xOffset;
int y = (int) event.getY() - yOffset;
Log.i(TAG, "Touch image coordinates: (" + x + ", " + y + ")");
if ((x < 0) || (y < 0) || (x > cols) || (y > rows)) return false;
Rect touchedRect = new Rect();
touchedRect.x = (x > 4) ? x - 4 : 0;
touchedRect.y = (y > 4) ? y - 4 : 0;
touchedRect.width = (x + 4 < cols) ? x + 4 - touchedRect.x : cols - touchedRect.x;
touchedRect.height = (y + 4 < rows) ? y + 4 - touchedRect.y : rows - touchedRect.y;
Mat touchedRegionRgba = mRgba.submat(touchedRect);
Mat touchedRegionHsv = new Mat();
Imgproc.cvtColor(touchedRegionRgba, touchedRegionHsv, Imgproc.COLOR_RGB2HSV_FULL);
// Calculate average color of touched region
mBlobColorHsv = Core.sumElems(touchedRegionHsv);
int pointCount = touchedRect.width * touchedRect.height;
for (int i = 0; i < mBlobColorHsv.val.length; i++)
mBlobColorHsv.val[i] /= pointCount;
mBlobColorRgba = converScalarHsv2Rgba(mBlobColorHsv);
mColor = mBlobColorRgba.val[0] + ", " + mBlobColorRgba.val[1] + ", " + mBlobColorRgba.val[2] + ", " + mBlobColorRgba.val[3];
Log.i(TAG, "Touched rgba color: (" + mBlobColorRgba.val[0] + ", " + mBlobColorRgba.val[1] +
", " + mBlobColorRgba.val[2] + ", " + mBlobColorRgba.val[3] + ")");
mRGBA is a mat object which was initiated in onCameraViewStarted as
mRgba = new Mat(height, width, CvType.CV_8UC4);
And for the 2nd part:
2- Find on the camera shapes like triangles, squares or circles based
on the color choosed before.
I have tried to find out the selected contours shape using approxPolyDP
MatOfPoint2f contour2f = new MatOfPoint2f(contours.get(0).toArray());
//Processing on mMOP2f1 which is in type MatOfPoint2f
double approxDistance = Imgproc.arcLength(contour2f, true) * 0.02;
Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);
//Convert back to MatOfPoint
MatOfPoint points = new MatOfPoint(approxCurve.toArray());
System.out.println("points length" + points.toArray().length);
if( points.toArray().length == 5)
{
System.out.println("Pentagon");
mShape = "Pentagon";
}
else if(points.toArray().length > 5)
{
System.out.println("Circle");
Imgproc.drawContours(mRgba, contours, 0, new Scalar(255, 255, 0, -1));
mShape = "Circle";
}
else if(points.toArray().length == 4)
{
System.out.println("Square");
mShape = "Square";
}
else if(points.toArray().length == 4)
{
System.out.println("Triangle");
mShape = "Triangle";
}
This was done on onCameraFrame function after i obtained the contour list
For me if the length of point array was more than 5 it was usually a circle. But there is other algorithm to obtain circle and its attributes.
I am new to android and building an app which involves displaying a view for 2 seconds and then change. Here's my onDraw method:
#Override
public void onDraw(Canvas canvas)
{
float level = game.level;
width = getWidth();
tile_length = width/level;
Paint rect = new Paint();
rect.setColor(getResources().getColor(R.color.dark));
canvas.drawRect(0, 0, width, width, rect);
game.numbers.setTextSize( (0.70f * tile_length));
game.numbers.setTextAlign(Paint.Align.CENTER);
grid.setColor(getResources().getColor(R.color.lines));
rect.setColor(getResources().getColor(R.color.tile_on));
int ind = 1;
int tile_num = 1;
FontMetrics fm = game.numbers.getFontMetrics();
float x = tile_length/2;
float y = tile_length/2 - (fm.ascent + fm.descent) / 2;
Log.v(LOG_TAG, "changed = " + game.changed);
for (int i=0; i<width; i+=tile_length)
{
for(int j=0; j<width; j+=tile_length)
{
for(int k = 0; k<level; k++ )
if(tile_num == game.random[k])
{
// Log.v(LOG_TAG, "i = " + i + "j = " + j);
game.set_Coordinates(ind-1, i, j);
String tile = Integer.toString(ind++);
canvas.drawRect(i, j, i+tile_length, j+tile_length, rect);
canvas.drawText(tile, i+x, j+y, game.numbers); //needs to be updated after 2 seconds
break;
}
tile_num++;
}
}
}
I understand i have to use postdelayed method somewhere, but don't know how...Now i just want to ommit the canvas.drawText line after the delay.
do you mean something like this
new Handler().postDelayed(new Runnable(){
public void run(){
// do something here like draw text;
}
}, 2000);
A timer is needed, indeed. What I do, which is very simple, is first to create records of coordinates (and any other data needed) for every point of the drawing -- instead of drawing the points on the spot -- and then reproduce them using a timer (Android handler, preferably, like the one suggested above). This also offers you a lot of possibilities while actual drawing: pause, go faster/slower, go backwards, ...
I don't know if this method can be used for complicated drawings, but it is fine for drawing shapes, curves, surfaces, etc.