I have try below code using OpenCV functions cvtColor,Canny and HoughLinesP but not able to get accurate result or not work in some cases.
private boolean opencvProcessCount(Uri picFileUri) {
hairCount = 0;
totalC = 0;
//Log.e(">>>>>>>>","count " + picFileUri);
try {
InputStream iStream = getContentResolver().openInputStream(picFileUri);
byte[] im = getBytes(iStream);
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inDither = true;
opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap image = BitmapFactory.decodeByteArray(im, 0, im.length);
Mat mYuv = new Mat();
Utils.bitmapToMat(image, mYuv);
Mat mRgba = new Mat();
Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_RGB2GRAY, 4);
Imgproc.Canny(mRgba, mRgba, 80, 90);
Mat lines = new Mat();
int threshold = 80;
int minLineSize = 30;
int lineGap = 100;
Imgproc.HoughLinesP(mRgba, lines, 1, Math.PI/180, threshold, minLineSize, lineGap);
for (int x = 0; x < lines.rows(); x++)
{
double[] vec = lines.get(x, 0);
double x1 = vec[0],
y1 = vec[1],
x2 = vec[2],
y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
double dx = x1 - x2;
double dy = y1 - y2;
double dist = Math.sqrt (dx*dx + dy*dy);
totalC ++;
Log.e(">>>>>>>>","dist " + dist);
if(dist>300.d)
{
hairCount ++;
// Log.e(">>>>>>>>","count " + x);
Imgproc.line(mRgba, start, end, new Scalar(0,255, 0, 255),5);// here initimg is the original image.
}// show those lines that have length greater than 300
}
Log.e(">>>>>>>>",totalC+" out hairCount " + hairCount);
// Imgproc.
} catch (Throwable e) {
// Log.e(">>>>>>>>","count " + e.getMessage());
e.printStackTrace();
}
return false;
}
Below are sample images to count hair :
I think you will find this article interesting:
http://www.cs.ubc.ca/~lowe/papers/aij87.pdf
They take a 2D bitmap, apply canny edge detector and then regroup segments of the different edges based on how likely they belong to a same object - in this case hair (and give criterias for such regrouping).
I think you could use this to know how many objects there are on the image, and if the image contains only hair, then you'd have a count for hair.
Related
Edited:
If anyone one can suggest any link or post, I will be very grateful. I am trying to find solution from two days and i can't find any.Thank you in advance.
I am trying to put one object(image) on particular location of screen Using openCv in android.
I do have Points like this "{680.0, 488.0}" which is having (x,y) coordinate,
So how can I find particular location in my screen for putting object ?
Below is my code where i am getting Point:
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
iThreshold = minTresholdSeekbar.getProgress();
//Imgproc.blur(mRgba, mRgba, new Size(5,5));
Imgproc.GaussianBlur(mRgba, mRgba, new org.opencv.core.Size(3, 3), 1, 1);
//Imgproc.medianBlur(mRgba, mRgba, 3);
if (!mIsColorSelected) return mRgba;
List<MatOfPoint> contours = mDetector.getContours();
mDetector.process(mRgba);
Log.d(TAG, "Contours count: " + contours.size());
if (contours.size() <= 0) {
return mRgba;
}
RotatedRect rect = Imgproc.minAreaRect(new MatOfPoint2f(contours.get(0).toArray()));
double boundWidth = rect.size.width;
double boundHeight = rect.size.height;
int boundPos = 0;
for (int i = 1; i < contours.size(); i++) {
rect = Imgproc.minAreaRect(new MatOfPoint2f(contours.get(i).toArray()));
if (rect.size.width * rect.size.height > boundWidth * boundHeight) {
boundWidth = rect.size.width;
boundHeight = rect.size.height;
boundPos = i;
}
}
Rect boundRect = Imgproc.boundingRect(new MatOfPoint(contours.get(boundPos).toArray()));
//Core/Imgproc.rectangle( mRgba, boundRect.tl(), boundRect.br(), CONTOUR_COLOR_WHITE, 2, 8, 0 );
Log.d(TAG,
" Row start [" +
(int) boundRect.tl().y + "] row end [" +
(int) boundRect.br().y + "] Col start [" +
(int) boundRect.tl().x + "] Col end [" +
(int) boundRect.br().x + "]");
int rectHeightThresh = 0;
double a = boundRect.br().y - boundRect.tl().y;
a = a * 0.7;
a = boundRect.tl().y + a;
Log.d(TAG,
" A [" + a + "] br y - tl y = [" + (boundRect.br().y - boundRect.tl().y) + "]");
//Core.rectangle( mRgba, boundRect.tl(), boundRect.br(), CONTOUR_COLOR, 2, 8, 0 );
//Core/Imgproc.rectangle( mRgba, boundRect.tl(), new Point(boundRect.br().x, a), CONTOUR_COLOR, 2, 8, 0 );
MatOfPoint2f pointMat = new MatOfPoint2f();
Imgproc.approxPolyDP(new MatOfPoint2f(contours.get(boundPos).toArray()), pointMat, 3, true);
contours.set(boundPos, new MatOfPoint(pointMat.toArray()));
MatOfInt hull = new MatOfInt();
MatOfInt4 convexDefect = new MatOfInt4();
Imgproc.convexHull(new MatOfPoint(contours.get(boundPos).toArray()), hull);
if (hull.toArray().length < 3) return mRgba;
Imgproc.convexityDefects(new MatOfPoint(contours.get(boundPos).toArray()), hull, convexDefect);
List<MatOfPoint> hullPoints = new LinkedList<MatOfPoint>();
List<Point> listPo = new LinkedList<Point>();
for (int j = 0; j < hull.toList().size(); j++) {
listPo.add(contours.get(boundPos).toList().get(hull.toList().get(j)));
}
MatOfPoint e = new MatOfPoint();
e.fromList(listPo);
hullPoints.add(e);
List<MatOfPoint> defectPoints = new LinkedList<MatOfPoint>();
List<Point> listPoDefect = new LinkedList<Point>();
for (int j = 0; j < convexDefect.toList().size(); j = j + 4) {
Point farPoint = contours.get(boundPos).toList().get(convexDefect.toList().get(j + 2));
Integer depth = convexDefect.toList().get(j + 3);
if (depth > iThreshold && farPoint.y < a) {
listPoDefect.add(contours.get(boundPos).toList().get(convexDefect.toList().get(j + 2)));
}
Log.d(TAG, "defects [" + j + "] " + convexDefect.toList().get(j + 3));
}
MatOfPoint e2 = new MatOfPoint();
e2.fromList(listPo);
defectPoints.add(e2);
Log.d(TAG, "hull: " + hull.toList());
Log.d(TAG, "defects: " + convexDefect.toList());
Imgproc.drawContours(mRgba, hullPoints, -1, CONTOUR_COLOR, 3);
int defectsTotal = (int) convexDefect.total();
Log.d(TAG, "Defect total " + defectsTotal);
this.numberOfFingers = listPoDefect.size();
if (this.numberOfFingers > 5) {
this.numberOfFingers = 5;
} /*else if (this.numberOfFingers == 1) {
this.numberOfFingers = 0;
}
*/
mHandler.post(mUpdateFingerCountResults);
runOnUiThread(new Runnable() {
#Override
public void run() {
ring.setVisibility(View.VISIBLE);
/*LinearLayout.LayoutParams parms = new LinearLayout.LayoutParams(10,10);
ring.setLayoutParams(parms);*/
}
});
for (Point p : listPoDefect) {
Log.e("Points", p.toString());
// Imgproc.circle(mRgba, p, 6, new Scalar(255,0,255));
}
return mRgba;
}
Below is the method which i have used to save image and display. Now i need to put ring on one of captured hand fingers.
private void saveImage() {
if (MainActivity.listPoDefect.size() >= 5) {
mIsColorSelected = false;
if (listPoDefect.size() != 0) {
for (Point p :listPoDefect) {
Log.d(TAG, "before sorting X =" + String.valueOf(p.x) + " Y = " + String.valueOf(p.y));
}
Collections.sort(listPoDefect, new Comparator<Point>() {
public int compare(Point o1, Point o2) {
return Double.compare(o1.x, o2.x);
}
});
Log.d(TAG, "After Sorting ");
for (Point p : listPoDefect) {
Log.d(TAG, "after sorting X =" + String.valueOf(p.x) + " Y = " + String.valueOf(p.y));
}
}
mIsColorSelected = false;
Bitmap bitmap5 = Bitmap.createBitmap(mRgbaWithoutLine.cols(), mRgbaWithoutLine.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgbaWithoutLine, bitmap5);
bitmap = bitmap5;
//Create a new image bitmap and attach a brand new canvas to it
Bitmap tempBitmap = Bitmap.createBitmap(bitmap5.getWidth(), bitmap5.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
//Draw the image bitmap into the cavas
tempCanvas.drawBitmap(bitmap5, 0, 0, null);
double scaledWidth = bitmap5.getWidth();
double scaledHeight = bitmap5.getHeight();
double xScaleFactor = scaledWidth / bitmap5.getWidth();
double yScaleFactor = scaledHeight / bitmap5.getHeight();
Paint myRectPaint = new Paint();
myRectPaint.setStyle(Paint.Style.STROKE);
myRectPaint.setColor(Color.RED);
myRectPaint.setStrokeWidth(5);
myRectPaint.setAntiAlias(true);
//this is zeroth position manipulation
double differenceX= listPoDefect.get(2).x-listPoDefect.get(1).x;
double differenceY= listPoDefect.get(2).y-listPoDefect.get(1).y;
double zeroPostionX=listPoDefect.get(1).x-differenceX;
double zeroPostionY=listPoDefect.get(1).y-differenceY;
Point pointZeroths=listPoDefect.get(0);
Point pointNew=new Point(zeroPostionX,zeroPostionY);
listPoDefect.remove(0);
listPoDefect.add(0,pointNew);
double thirdPostionX=listPoDefect.get(2).x+differenceX;
double thirdPostionY=listPoDefect.get(2).y+differenceY;
Point thirdpointNew=new Point(thirdPostionX,thirdPostionY);
listPoDefect.remove(3);
listPoDefect.add(3,thirdpointNew);
// Point pointNewThird=new Point(pointthird.x+differenc,pointthird.y);
// HomeActivity.listPoDefect.remove(3);
// HomeActivity.listPoDefect.add(3,pointNewThird);
Paint paint_text = new Paint();
paint_text.setColor(Color.WHITE);
paint_text.setStyle(Paint.Style.FILL);
paint_text.setTextSize(30);
for (int row = 0; row < 4; row++) { // draw 2 rows
Point point1 = null;
point1 = listPoDefect.get(row);
android.graphics.Point canvas_point1 = new android.graphics.Point((int) ((point1.x * xScaleFactor)), (int) ((point1.y * yScaleFactor)));
Log.d(TAG, "after sorting canvas_point1 ="+"Raw ="+row +" " + String.valueOf(canvas_point1.x) + " Y = " + String.valueOf(canvas_point1.y));
Log.d(TAG, "====================================================================================================");
if(pointFListGraphies.size()!=4)
{
pointFListGraphies.add(new PointF(canvas_point1));
}
// tempCanvas.drawRect(canvas_point1.x, canvas_point1.y, canvas_point1.x + 130, canvas_point1.y + 50, myRectPaint);
// tempCanvas.drawText(String.valueOf(row+"-"+canvas_point1.x), canvas_point1.x, canvas_point1.y, paint_text);
}
Log.d(TAG, "====================================================================================================");
for (int row = 0; row < pointFListGraphies.size(); row++) { // draw 2 rows
PointF point1 = null;
point1 = pointFListGraphies.get(row);
Log.d(TAG, "=========pointF X="+point1.x +"poninF Y =" +point1.y);
}
tempbitmap = tempBitmap;
handImage.setVisibility(View.VISIBLE);
handImage.setImageBitmap(tempbitmap);
/* Bitmap src = BitmapFactory.decodeResource(getResources(), R.drawable.ring);
tempCanvas.drawBitmap();*/
onCameraViewStopped();
//finish();
}
else {
}
}
Can anyone help me?
Thanks in advance.
OpenCV has a number of functions for writing on an image, which is usually what you are displaying on the screen.
FOr example the function to write text a particular location is
void cv::putText ( InputOutputArray img,
const String & text,
Point org,
int fontFace,
double fontScale,
Scalar color,
int thickness = 1,
int lineType = LINE_8,
bool bottomLeftOrigin = false
)
The parameters are:
Parameters
img Image.
text Text string to be drawn.
org Bottom-left corner of the text string in the image.
fontFace Font type, see cv::HersheyFonts.
fontScale Font scale factor that is multiplied by the font-specific base size.
color Text color.
thickness Thickness of the lines used to draw a text.
lineType Line type. See the line for details.
bottomLeftOrigin When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner.
You can find an overview of the drawing function here: https://docs.opencv.org/3.1.0/dc/da5/tutorial_py_drawing_functions.html
In your case, so long as your image covers the whole screen this allows you plot exactly where you want the text, or object or whatever you want too draw to appear.
I am trying to use this code http://androiderstuffs.blogspot.com/2016/06/detecting-rectangle-using-opencv-java.html to detect card. But instead of putting card on plane surface, I will be holding this card in hand in-front of my Head. Problem is, its not detecting card rectangle. I am new to OpenCV. See my code below, this code will highlight all found rectangles in output image. Problem is, it never find card rectangle.
private void findRectangleOpen(Bitmap image) throws Exception {
Mat tempor = new Mat();
Mat src = new Mat();
Utils.bitmapToMat(image, tempor);
Imgproc.cvtColor(tempor, src, Imgproc.COLOR_BGR2RGB);
Mat blurred = src.clone();
Imgproc.medianBlur(src, blurred, 9);
Mat gray0 = new Mat(blurred.size(), CvType.CV_8U), gray = new Mat();
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<Mat> blurredChannel = new ArrayList<Mat>();
blurredChannel.add(blurred);
List<Mat> gray0Channel = new ArrayList<Mat>();
gray0Channel.add(gray0);
MatOfPoint2f approxCurve;
int maxId = -1;
for (int c = 0; c < 3; c++) {
int ch[] = {c, 0};
Core.mixChannels(blurredChannel, gray0Channel, new MatOfInt(ch));
int thresholdLevel = 1;
for (int t = 0; t < thresholdLevel; t++) {
if (t == 0) {
Imgproc.Canny(gray0, gray, 10, 20, 3, true); // true ?
Imgproc.dilate(gray, gray, new Mat(), new Point(-1, -1), 1); // 1
// ?
} else {
Imgproc.adaptiveThreshold(gray0, gray, thresholdLevel,
Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
Imgproc.THRESH_BINARY,
(src.width() + src.height()) / 200, t);
}
Imgproc.findContours(gray, contours, new Mat(),
Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
int i = 0;
for (MatOfPoint contour : contours) {
MatOfPoint2f temp = new MatOfPoint2f(contour.toArray());
double area = Imgproc.contourArea(contour);
approxCurve = new MatOfPoint2f();
Imgproc.approxPolyDP(temp, approxCurve,
Imgproc.arcLength(temp, true) * 0.02, true);
if (approxCurve.total() == 4 && area >= 200 && area <= 40000) {
double maxCosine = 0;
List<Point> curves = approxCurve.toList();
for (int j = 2; j < 5; j++) {
double cosine = Math.abs(angle(curves.get(j % 4),
curves.get(j - 2), curves.get(j - 1)));
maxCosine = Math.max(maxCosine, cosine);
}
if (maxCosine < 0.3) {
Imgproc.drawContours(src, contours, i, new Scalar(255, 0, 0), 3);
Bitmap bmp;
bmp = Bitmap.createBitmap(src.cols(), src.rows(),
Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, bmp);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
//File origFile = getFileForSaving();
savePhoto(byteArray);
bmp.recycle();
}
}
i++;
}
}
}
}
private static double angle(org.opencv.core.Point p1, org.opencv.core.Point p2, org.opencv.core.Point p0) {
double dx1 = p1.x - p0.x;
double dy1 = p1.y - p0.y;
double dx2 = p2.x - p0.x;
double dy2 = p2.y - p0.y;
return (dx1 * dx2 + dy1 * dy2)
/ sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2)
+ 1e-10);
}
Sample output image is:
Output of detecting rectangle
This is the exception im getting
CvException [org.opencv.core.CvException: cv::Exception: /hdd2/buildbot/slaves/slave_ardbeg1/50-SDK/opencv/modules/imgproc/src/hough.cpp:712: error: (-5) The source image must be 8-bit, single-channel in function CvSeq* cvHoughLines2(CvArr*, void*, int, double, double, int, double, double)
mat = new Mat();
edges = new Mat();
lines = new Mat();
mRgba = new Mat(612, 816, CvType.CV_8UC1);
Utils.bitmapToMat(bitmap, mat);
Imgproc.Canny(mat, edges, 50, 90);
int threshold = 50;
int minLineSize = 20;
int lineGap = 20;
try {
Imgproc.HoughLines(mat, lines, 1, Math.PI / 180, threshold, minLineSize, lineGap);
for (int x = 0; x < lines.cols(); x++) {
double[] vec = lines.get(0, x);
double x1 = vec[0], y1 = vec[1], x2 = vec[2], y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
Core.line(mRgba, start, end, new Scalar(255, 0, 0), 3);
}
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgba, bmp);
bitmap = bmp;
} catch (Exception e) {
e.printStackTrace();
System.out.println("e = " + e);
}
Your image in function HoughLines isn't right. You're not formatting it right before putting it into the function.
Try prepare image like this:
https://stackoverflow.com/a/7975315/5577679
I am working on an android app. I can detect lines using Canny and Hough transform but I don't know how to get the angles and lengths of the detected lines, can you help please? Here's the code:
public void countStraightLines(View view) {
try{
int iCannyLowerThreshold = 45;
int iCannyUpperThreshold = 75;
Mat rgba = Utils.loadResource(getApplicationContext(), res);
Bitmap bmp = Bitmap.createBitmap(rgba.width(), rgba.height(), Bitmap.Config.ARGB_8888);
Mat gray = new Mat ();
Imgproc.cvtColor(rgba, gray, Imgproc.COLOR_BGRA2GRAY, 4);
Imgproc.Canny(gray, gray, iCannyLowerThreshold, iCannyUpperThreshold);
Utils.matToBitmap(gray, bmp);
imgSource.setImageBitmap(bmp);
} catch (IOException e) {
Log.e(TAG, "ERROR Loading Mat");
e.printStackTrace();
}
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position,
long id) {
Globals.pictSelected=parent.getItemAtPosition(position).toString();
res = getResources().getIdentifier(parent.getItemAtPosition(position).toString(), "drawable", this.getPackageName());
try {
Mat rgba = Utils.loadResource(getApplicationContext(), res);
Bitmap bmp = Bitmap.createBitmap(rgba.width(), rgba.height(), Bitmap.Config.ARGB_8888);
Mat gray = new Mat ();
Imgproc.cvtColor(rgba, gray, Imgproc.COLOR_BGRA2GRAY, 4);
int iCannyLowerThreshold = 45;
int iCannyUpperThreshold = 75;
int iHoughLinesThreshold = 50;
int iHoughLinesMinLineSize = 40;
int iHoughLinesGap = 20;
Imgproc.Canny(gray, gray, iCannyLowerThreshold, iCannyUpperThreshold);
Mat lines = new Mat();
Imgproc.HoughLinesP(gray, lines, 1, Math.PI/180, iHoughLinesThreshold, iHoughLinesMinLineSize, iHoughLinesGap);
int x = 0;
char s = 'N';
for (; x < Math.min(lines.cols(), 100); x++)
{
double[] vec = lines.get(0, x);
if (vec == null)
break;
double x1 = vec[0], y1 = vec[1], x2 = vec[2], y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
Core.line(rgba, start, end, new Scalar(255, 0, 0, 255), 1);
if (x >= 40){s = 'C';}
else {s = 'S';}
}
text.setText("Line Count: " + x + " and The Picture is " + s);
Utils.matToBitmap(rgba, bmp);
imgSource.setImageBitmap(bmp);
} catch (IOException e) {
Log.e(TAG, "ERROR Loading Mat");
e.printStackTrace();
}
}
Thank you!
Well, it looks like you have a start point and an end point- the length is just ((starty-endy)^2+(startx-endx)^2)^(1/2). You can get the angle between them by using the fact that the dot product of two vectors A and B A.B=|A|*|B|*cos(alpha) where alpha is the angle between them. So alpha= arccos((A.B)/(|A|*|B|)).
i have an app that places a fisheye distortion effect on a bitmap. to create the distortion i must loop through the entire bitmap checking whether a given pixel falls with a circle bounds. if it does then i manipulate that pixel. This process is labour intensive and takes upto 50 secs. i was thinking of different ways to do this so i don't have to loop through the whole bitmap to apply the effect.
one idea i have is to draw the bitmap first and display it. then create a second bitmap overlay which only has the effect on. i could then overlay the second bitmap on the first. i'm just trying to think of ways in which i can apply this effect without looping through as many pixels to speed things up. i'll post the distortion class. thanks.
.
class Filters{
private float xscale;
private float yscale;
private float xshift;
private float yshift;
private int [] s;
private int [] scalar;
private int [] s1;
private int [] s2;
private int [] s3;
private int [] s4;
private String TAG = "Filters";
long getRadXStart = 0;
long getRadXEnd = 0;
long startSample = 0;
long endSample = 0;
public Filters(){
Log.e(TAG, "***********inside filter constructor");
s = new int[4];
scalar = new int[4];
s1 = new int[4];
s2 = new int[4];
s3 = new int[4];
s4 = new int[4];
}
public Bitmap barrel (Bitmap input, float k,float cenx, float ceny){
//Log.e(TAG, "***********INSIDE BARREL METHOD ");
Debug.startMethodTracing("barrel");
//float centerX=input.getWidth()/2; //center of distortion
//float centerY=input.getHeight()/2;
float centerX=cenx;
float centerY=ceny;
int width = input.getWidth(); //image bounds
int height = input.getHeight();
Bitmap dst = Bitmap.createBitmap(width, height,input.getConfig() ); //output pic
// Log.e(TAG, "***********dst bitmap created ");
xshift = calc_shift(0,centerX-1,centerX,k);
float newcenterX = width-centerX;
float xshift_2 = calc_shift(0,newcenterX-1,newcenterX,k);
yshift = calc_shift(0,centerY-1,centerY,k);
float newcenterY = height-centerY;
float yshift_2 = calc_shift(0,newcenterY-1,newcenterY,k);
xscale = (width-xshift-xshift_2)/width;
// Log.e(TAG, "***********xscale ="+xscale);
yscale = (height-yshift-yshift_2)/height;
// Log.e(TAG, "***********yscale ="+yscale);
// Log.e(TAG, "***********filter.barrel() about to loop through bm");
/*for(int j=0;j<dst.getHeight();j++){
for(int i=0;i<dst.getWidth();i++){
float x = getRadialX((float)i,(float)j,centerX,centerY,k);
float y = getRadialY((float)i,(float)j,centerX,centerY,k);
sampleImage(input,x,y);
int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
// System.out.print(i+" "+j+" \\");
dst.setPixel(i, j, color);
}
}*/
int origPixel;
long startLoop = System.currentTimeMillis();
for(int j=0;j<dst.getHeight();j++){
for(int i=0;i<dst.getWidth();i++){
origPixel= input.getPixel(i,j);
getRadXStart = System.currentTimeMillis();
float x = getRadialX((float)j,(float)i,centerX,centerY,k);
getRadXEnd= System.currentTimeMillis();
float y = getRadialY((float)j,(float)i,centerX,centerY,k);
sampleImage(input,x,y);
int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
// System.out.print(i+" "+j+" \\");
//if( Math.sqrt( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) ) <= 150 ){
if( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) <= 22500 ){
dst.setPixel(i, j, color);
}else{
dst.setPixel(i,j,origPixel);
}
}
}
long endLoop = System.currentTimeMillis();
long loopDuration = endLoop - startLoop;
long radXDuration = getRadXEnd - getRadXStart;
long sampleDur = endSample - startSample;
Log.e(TAG, "sample method took "+sampleDur+"ms");
Log.e(TAG, "getRadialX took "+radXDuration+"ms");
Log.e(TAG, "loop took "+loopDuration+"ms");
// Log.e(TAG, "***********filter.barrel() looped through bm about to return dst bm");
Debug.stopMethodTracing();
return dst;
}
void sampleImage(Bitmap arr, float idx0, float idx1)
{
startSample = System.currentTimeMillis();
// s = new int [4];
if(idx0<0 || idx1<0 || idx0>(arr.getHeight()-1) || idx1>(arr.getWidth()-1)){
s[0]=0;
s[1]=0;
s[2]=0;
s[3]=0;
return;
}
float idx0_fl=(float) Math.floor(idx0);
float idx0_cl=(float) Math.ceil(idx0);
float idx1_fl=(float) Math.floor(idx1);
float idx1_cl=(float) Math.ceil(idx1);
/* float idx0_fl=idx0;
float idx0_cl=idx0;
float idx1_fl=idx1;
float idx1_cl=idx1;*/
/* int [] s1 = getARGB(arr,(int)idx0_fl,(int)idx1_fl);
int [] s2 = getARGB(arr,(int)idx0_fl,(int)idx1_cl);
int [] s3 = getARGB(arr,(int)idx0_cl,(int)idx1_cl);
int [] s4 = getARGB(arr,(int)idx0_cl,(int)idx1_fl);*/
s1 = getARGB(arr,(int)idx0_fl,(int)idx1_fl);
s2 = getARGB(arr,(int)idx0_fl,(int)idx1_cl);
s3 = getARGB(arr,(int)idx0_cl,(int)idx1_cl);
s4 = getARGB(arr,(int)idx0_cl,(int)idx1_fl);
float x = idx0 - idx0_fl;
float y = idx1 - idx1_fl;
s[0]= (int) (s1[0]*(1-x)*(1-y) + s2[0]*(1-x)*y + s3[0]*x*y + s4[0]*x*(1-y));
s[1]= (int) (s1[1]*(1-x)*(1-y) + s2[1]*(1-x)*y + s3[1]*x*y + s4[1]*x*(1-y));
s[2]= (int) (s1[2]*(1-x)*(1-y) + s2[2]*(1-x)*y + s3[2]*x*y + s4[2]*x*(1-y));
s[3]= (int) (s1[3]*(1-x)*(1-y) + s2[3]*(1-x)*y + s3[3]*x*y + s4[3]*x*(1-y));
endSample = System.currentTimeMillis();
}
int [] getARGB(Bitmap buf,int x, int y){
int rgb = buf.getPixel(y, x); // Returns by default ARGB.
// int [] scalar = new int[4];
scalar[0] = (rgb >>> 24) & 0xFF;
scalar[1] = (rgb >>> 16) & 0xFF;
scalar[2] = (rgb >>> 8) & 0xFF;
scalar[3] = (rgb >>> 0) & 0xFF;
return scalar;
}
float getRadialX(float x,float y,float cx,float cy,float k){
x = (x*xscale+xshift);
y = (y*yscale+yshift);
float res = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
return res;
}
float getRadialY(float x,float y,float cx,float cy,float k){
x = (x*xscale+xshift);
y = (y*yscale+yshift);
float res = y+((y-cy)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
return res;
}
float thresh = 1;
float calc_shift(float x1,float x2,float cx,float k){
float x3 = (float)(x1+(x2-x1)*0.5);
float res1 = x1+((x1-cx)*k*((x1-cx)*(x1-cx)));
float res3 = x3+((x3-cx)*k*((x3-cx)*(x3-cx)));
if(res1>-thresh && res1 < thresh)
return x1;
if(res3<0){
return calc_shift(x3,x2,cx,k);
}
else{
return calc_shift(x1,x3,cx,k);
}
}
}// end of filters class
.
[update]
Hi, i've not watched all the vid cos i've only so much data allowance on dongle so going to wait till at work to watch it. I've modified the code to the one below. This stores the pixel data in an int array, so there's no call to dst.setPixel. it's still very slow(14 secs on 3.2MP camera) not at all like a few seconds as your code does. can you share that code or tell me if this is not what you meant. thanks Matt.
int origPixel = 0;
int []arr = new int[input.getWidth()*input.getHeight()];
int color = 0;
int p = 0;
int i = 0;
for(int j=0;j<dst.getHeight();j++){
for( i=0;i<dst.getWidth();i++,p++){
origPixel= input.getPixel(i,j);
float x = getRadialX((float)j,(float)i,centerX,centerY,k);
float y = getRadialY((float)j,(float)i,centerX,centerY,k);
sampleImage(input,x,y);
color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
// System.out.print(i+" "+j+" \\");
//if( Math.sqrt( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) ) <= 150 ){
if( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) <= 22500 ){
//dst.setPixel(i, j, color);
arr[p]=color;
Log.e(TAG, "***********arr = " +arr[i]+" i = "+i);
}else{
//dst.setPixel(i,j,origPixel);
arr[p]=origPixel;
}
}
}
// Log.e(TAG, "***********filter.barrel() looped through bm about to return dst bm");
Debug.stopMethodTracing();
Bitmap dst2 = Bitmap.createBitmap(arr,width,height,input.getConfig());
return dst2;
}
I bet you'd cut down considerably on your execution time if you eliminated the call to dst.setPixel inside your inner loop. Instead of operating on the Bitmaps inside your loop, stuff the values into integer arrays during your loop and call setPixels at the end passing in the array.
I have image manipulation code that can loop through an entire 2MP image in a few seconds.
On older Android api's (I believe earlier than 2.3, but it might even include 2.3), the actual image data does not reside in the managed heap so there's probably some expensive operation going on to find the actual location of the bits you're overwriting in the call to setPixel. The source of my information is the Google I/O 2011 video on memory management in Android. If you're doing this kind of work in Android, it's a must watch:
http://www.youtube.com/watch?v=_CruQY55HOk