Android从位图获取正确的像素

时间:2013-09-17 12:43:28

标签: android map bitmap projection getpixel

我在美国有一个温度位图,可以显示为地图叠加层。该部分工作正常 - 位图温度叠加完美地位于地图上相对于边界和地理点。

我的目标是能够点击此温度位图,然后根据该像素颜色输出温度。位图叠加层将根据当前地图投影进行缩放和定位。我在点击时获取位图像素的解决方案要求我使用地理点向后移动,考虑缩放,然后从原始位图图像中检索点击点。

点击工作正常,但我注意到哪些像素被检索不准确。例如,我可以点击位图的可见部分下方(如墨西哥)并仍然返回彩色像素 - 相反,在地图的顶部(加拿大附近),我可以点击可见的位图而不返回任何像素。就好像返回的像素值都向南移动了大约50英里。当缩小时误差不是很大或很明显,但是当放大时它们变得很明显,因为显然会返回错误的像素(温度)值。

我认为我的方法很合理,但我想知道我正在处理的大数字是否会导致“双打”问题。我是否需要切换到BigDecimal(没有经验)或其他数字格式?有更好的方法吗?

以下代码>>>>

public class BitmapOverlay extends Overlay {

Bitmap bmp;
Bitmap bmp2;
Context mContext;
GeoPoint upperLeft;
GeoPoint lowerRight;
Paint paint;
Paint lpaint;
Point ppupperLeft;
Point pplowerRight;
Rect src;
Rect src2;
Rect dst;
int frame;
int complete=100;

boolean shadow;
AnimationDrawable animation;
ImageView radarView;

Double W=(-129.357400913)* 1E6;
Double S=(23.560962423770285)* 1E6;
Double E=(-64.6787004566)* 1E6;
Double N=(50.3092170302897)* 1E6;

Projection currentProjection;

boolean mExternalStorageAvailable = false;
String fullPath;

boolean running;

public BitmapOverlay (Context freshContext){

    paint = new Paint(Paint.FILTER_BITMAP_FLAG);

    paint.setAntiAlias(true);
    paint.setFilterBitmap(true);
    paint.setDither(true);



    String state = Environment.getExternalStorageState();

    if (Environment.MEDIA_MOUNTED.equals(state)) {
    // We can read and write the media
    mExternalStorageAvailable = true;

    Log.i("isSdReadable", "External storage card is readable.");

    } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
    // We can only read the media
    Log.i("isSdReadable", "External storage card is readable.");
    mExternalStorageAvailable = true;
    } else {
    // Something else is wrong. It may be one of many other
    // states, but all we need to know is we can neither read nor write
    mExternalStorageAvailable = false;
    }








    upperLeft=new GeoPoint(N.intValue(),W.intValue());
    lowerRight=new GeoPoint(S.intValue(),E.intValue());


    ppupperLeft = new Point();
    pplowerRight = new Point();



    mContext=freshContext;




}






public void UpdateFrame(int sentframe , String ET){
    frame=sentframe;
//  complete=sentcomplete;




    if ( mExternalStorageAvailable == true) {

    //  Log.i("MyRadarOverlay", "got BMP Frame="+frame);

        //have to convert complete to frame to sequence... otherwise it gets to 5     
and stops..
        //might need to figure better wayt o tell when bmp is done
        //complete=frame-1;

        if (ET.equals("temp")){fullPath =  
Environment.getExternalStorageDirectory().getAbsolutePath() +  
                "/Pictures/ti0.png";}

        if (ET.equals("radar")){fullPath = 
Environment.getExternalStorageDirectory().getAbsolutePath() +  
                "/Pictures/ri"+frame+".png";}



        // Look for the file on the external storage
        try {



        bmp = BitmapFactory.decodeFile(fullPath);
        //}
        } catch (Exception e) {
        Log.e("getThumbnail() on external storage", e.getMessage());
        }


        if (ET.equals("radar")){    
        fullPath = Environment.getExternalStorageDirectory().getAbsolutePath() +  
                "/Pictures/si"+frame+".png";

    //  Log.i("MyRadarOverlay", "sifile path="+fullPath);

        // Look for the file on the external storage
        try {
        //if (tools.isSdReadable() == true) {

        bmp2 = BitmapFactory.decodeFile(fullPath);
        //}
        } catch (Exception e) {
        Log.e("getThumbnail() on external storage", e.getMessage());
        }
        //end of second if et == radar
 }

    }



}




  public void draw(Canvas canvas, MapView mapView, boolean shadow) {



    currentProjection=mapView.getProjection();

    currentProjection.toPixels(upperLeft, ppupperLeft);
    currentProjection.toPixels(lowerRight, pplowerRight);



    dst = new Rect( ppupperLeft.x, ppupperLeft.y, pplowerRight.x, pplowerRight.y );

    if (bmp2 != null ){

        src = new Rect( 0,0, bmp2.getWidth() , bmp2.getHeight()  );

        canvas.drawBitmap(bmp2, src, dst, paint);


      } 



  if (bmp != null ){


    src = new Rect( 0,0, bmp.getWidth() , bmp.getHeight()  );

    canvas.drawBitmap(bmp, src, dst, paint);



  } 



}




//###################ON TAP#################################   


@Override
public boolean onTap( GeoPoint geoPoint, MapView mapView) {



//  Log.i("My Info", "overlay-on tap called");
     Log.i("BITMAP OVERALY", "TAP at"+geoPoint);     

 //  take left lon add right lon...add basically get a range of lons that the point can  
fall under//
//   if it falls within the range get the percentage ...


 //  the start left most lon is equivalent to 0 the right most is equavalent to the 
width--1600
//   find the relative position on that range

     double xpixel=0;
     double ypixel=0;

     double latgeopoint=geoPoint.getLatitudeE6();
     double longeopoint=geoPoint.getLongitudeE6();


    //find out if it is within longitude range of bitmap
    if (longeopoint>W && longeopoint<E){
        //find out if it is within latitude range of bitmap
        if (latgeopoint>S && latgeopoint<N){

        Log.i("BITMAP OVERALY", "passed if statement- 
lon,lat"+longeopoint+","+latgeopoint);

        //work  on lon side
        double lonrange=W-longeopoint;
        Log.i("BITMAP OVERALY", "lonrange="+lonrange);

        //-64678700456
        double lonratio=lonrange/W-E;
        Log.i("BITMAP OVERALY", "lonratio="+lonratio);

        xpixel=lonratio*bmp.getWidth();
        Log.i("BITMAP OVERALY", "xpixel="+xpixel);

        //work on lat side

        double latrange=N-latgeopoint;
        Log.i("BITMAP OVERALY", "latrange="+latrange);

        //26748254607
        double latratio=latrange/N-S;
        Log.i("BITMAP OVERALY", "latratio="+latratio);

        ypixel=latratio*bmp.getHeight();
        Log.i("BITMAP OVERALY", "ypixel="+ypixel);


        //end if lat
        }
    //end if lon    
    }


     //convert doubles to ints
    int pixelx = (int)xpixel;
    int pixely = (int)ypixel;

    Log.i("BITMAP OVERALY", "pixelx,pixely="+pixelx+","+pixely);



    int pixel = bmp.getPixel(pixelx, pixely);



    int redValue = Color.red(pixel);
    int greenValue = Color.green(pixel);
    int blueValue = Color.blue(pixel);

    float[] hsv = new float[3];
    Color.RGBToHSV(redValue, greenValue, blueValue, hsv);

    String mytemp="";



    if (hsv[0]<5){mytemp="Greater than 110";}
    if (hsv[0]<=20 && hsv[0]>5){mytemp="100 to 110";}
    if (hsv[0]<=45 && hsv[0]>20){mytemp="90 to 100";}
    if (hsv[0]<=60 && hsv[0]>45){mytemp="80 to 90";}
    if (hsv[0]<=80 && hsv[0]>60){mytemp="70 to 80";}
    if (hsv[0]<=120 && hsv[0]>80){mytemp="60 to 70";}
    if (hsv[0]<=150 && hsv[0]>120){mytemp="50 to 60";}







            AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);


              dialog.setNegativeButton("Close",
                      new DialogInterface.OnClickListener() {
                          public void onClick(DialogInterface dialog, int id) {

                                dialog.cancel();

                          }
                      });


              dialog.setTitle("BITMAP TAP hsv=" + hsv[0] + " " + hsv[1] + " " + 
hsv[2] + " TEMP="+mytemp);



              dialog.show();



    return false; 
 //end on tap   
} 



}

1 个答案:

答案 0 :(得分:0)

如果其他人偶然发现了这一点 - 我找到了解决方案。显然,错误是由于发生了web mercator映射转换。我覆盖在地图上的位图只能在远北和南边界准确。那是错误为零的地方。我越接近我的位图相对于纬度的中点,误差就越大。我能够通过在位图上绘制一组像素然后将它们与已知的lat线进行比较来量化中点处的误差。在这种特殊情况下,误差在中点处约为54个像素。我还在已知的纬度上测试了南北方的一些其他点,以便创建错误数据集。现在,我知道我的错误,我可以插入一个修正,以应用于每个特定的纬度。为了准确插值,我正在使用Cubic插值。