简体   繁体   English

Android从位图获取正确的像素

[英]Android Getting Correct Pixel from Bitmap

I have a bitmap of temperatures across the US that gets displayed as a map overlay. 我有整个美国的温度位图,这些位图显示为地图叠加层。 That part works fine- the Bitmap temperature overlay sits perfectly on the map relative to borders and geographic points. 该部分可以正常工作-位图温度叠加层相对于边界和地理位置完全位于地图上。

My goal is to be able to tap this temperature bitmap and then output the temperature based on that pixel color. 我的目标是能够点按该温度位图,然后根据该像素颜色输出温度。 The Bitmap overlay is getting scaled and positioned based on the current map projection. 位图叠加层将根据当前地图投影进行缩放和定位。 My solution to getting the bitmap pixel when tapped requires me to go backwards with a geopoint, account for scaling, and then retrieve the tapped point from the original bitmap image. 我要在点击时获取位图像素的解决方案要求我向后移动一个Geopoint,进行缩放,然后从原始位图图像中获取点击点。

The tapping works fine but I have noticed inaccuracies as far as which pixel is retrieved. 点击工作正常,但我注意到就检索到的像素而言不准确。 For example I can tap below the visible part of the bitmap (like in mexico) and still return a colored pixel- Conversely at the top of the map (near Canada) I can tap on the visible bitmap and not return any pixels. 例如,我可以点击位图的可见部分下方(如在墨西哥),并且仍然返回彩色像素-相反,在地图顶部(加拿大附近),我可以点击可见位图,而不返回任何像素。 It is as if the returned pixel values are all shifted south by about 50 miles. 好像返回的像素值全部向南移动了约50英里。 The errors aren't huge or obvious when zoomed out but when zoomed in they become obvious as obviously wrong pixel (temperature) values are returned. 当缩小时,误差不是很大或不明显,但是当返回错误的像素(温度)值时,放大时误差将变得明显。

I think my method is sound but I am wondering if the large numbers I am dealing with are causing problems with "doubles". 我认为我的方法是正确的,但是我想知道我处理的大量数字是否导致“双打”问题。 Do I need to switch to BigDecimal (no experience there) or some other number format? 我需要切换到BigDecimal(那里没有经验)或其他数字格式吗? Is there a better way to do this? 有一个更好的方法吗?

CODE BELOW>>>> 代码如下>>>>

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   
} 



}

In case anyone else stumbles upon this- I found a solution. 万一其他人偶然发现这个问题,我找到了解决方案。 Apparently the error is due to the web mercator map translation that takes place. 显然,该错误是由于进行了Web墨卡托地图翻译造成的。 The bitmap I am overlaying upon the map is only accurate at the far north and south bounds. 我叠加在地图上的位图仅在远北和南边界是准确的。 That is where the error is zero. 那就是误差为零的地方。 The closer I go to the midpoint of my bitmap relative to latitude the error grows. 我越靠近位图的中点(相对于纬度),误差就会增加。 I was able to quantify the error at the mid point by drawing a set of pixels on the bitmap and then comparing them to known lat lines. 通过在位图上绘制一组像素,然后将它们与已知的纬度线进行比较,我能够量化中点的误差。 In this particular case the error was about 54 pixels at the midpoint. 在此特定情况下,中点处的误差约为54个像素。 I also tested a few other points north and south at known latitudes in order to create a dataset of error. 为了创建误差数据集,我还测试了已知纬度下的其他一些南北方向点。 Now that I know my error I can interpolate a correction to apply at each particular latitude. 现在,我知道了自己的错误,可以对每个特定纬度进行插补以应用修正了。 In order to accurately interpolate I am using Cubic Interpolation. 为了精确插值,我使用三次插值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM