Android获取两张图片重叠部分,并融合

最近遇到一个需求,在Android设备上采集到的红外热图,由于像素比较低(60x80),无法看清楚拍摄的内容,经过讨论,决定将红外热图覆盖在可见光图上进行展示。但是可见光相机和红外相机位置存在偏差,实际上拍摄的两张图片不能直接进行覆盖。所以在覆盖之前,需要手动两张图片进行校准。这就是本文所要展示的内容。

难点

这个需求最大的难点就是,如何得到两张图片重叠的部分。
1.在屏幕上绘制可见光照片,自适应屏幕。
2.绘制红外热图。红外图在绘制的时候设置一个透明度,可以透过红外图隐约看到可见光图,方便移动重叠。
3.缩放和移动红外热图,让红外图和可见光图重叠。实际上可见光图比红外图大的多,所以必然有有一部分可见光图片没有被红外图覆盖。

4.切割两张图片重叠的部分,生成新的图片。

第一步,很简单,没什么好说的
第二步,在我另一篇博客里有详细介绍 Android控制图片在屏幕内缩放和移动
第三步,同上。

第四步,这是本篇的重点和难点。如何确定和切割两张图片的重叠部分。

获取重叠部分的原理

以可将光图为参照,计算红外热图的相对位置,然后进行切割,示意图如下。

    

(x1,y1)为可见光图绘制原点,(x2,y2)为红外热图绘制原点。两张图坐标原点的差值为diffX,diffY。可见光图的宽高方便时bigW、bigH。

红外热图相对于可见图的在X轴上的相对位为diffX/bigW,Y轴的相对位置为diffY/bigH。这里红外热图的原点可以在红外热图之外,也就是diffX和diffY可以为负数,但是两张图必须有重叠部分。

android手机的坐标原点在屏幕左上角,x轴往右越大,y轴往下越大。所以,重叠部分坐标应该是:x轴方向右侧两点坐标取大值,左侧取小值。y轴方向上边两点坐标取大值,下边两点坐标取小值。以这个为计算原理,计算重叠部分坐标。

计算得到重叠部分

在计算矩形坐标时,通常会用到Rect类,以方便记录矩形的四点坐标。这个类只有四个参数,如:new Rect(a, b, c, d)。


a:AC点的x坐标

b:AB点的y坐标

c:BD点的x坐标

d:CD点的y坐标

所以A(a, b),B(c, b),C(a, d),D(c, d);

已Rect存储两张图片四点的坐标,以可见光图的左上角为(0,0)点,计算出重叠部分的坐标。

代码如下

/**
     * 融合图裁剪
     * @param big  底图
     * @param small 小图
     * @param xInRatio 小图在底图中的横坐标(相对于底图宽的比例)
     * @param yInRatio 小图在底图中的纵坐标(相对于底图高的比例)
     * @param alpha 小图的透明度 0~255
     * @return
     */
   public static Bitmap mergeWithCrop(Bitmap big,Bitmap small,float xInRatio,float yInRatio,int alpha){
		
		int smallW = small.getWidth();
		int smallH = small.getHeight();
		int bigW = big.getWidth();
		int bigH = big.getHeight();
		
		int smallX = (int)(bigW*xInRatio);
		int smallY = (int)(bigH*yInRatio);		
		int bigX = 0;
		int bigY = 0;
		
		Rect sRect = new Rect(smallX, smallY, smallX+smallW, smallY+smallH);
		Rect bRect = new Rect(bigX, bigY, bigX+bigW, bigY+bigH);
		Rect overlap = intersect(sRect, bRect);
		
		int overlayW = overlap.right - overlap.left;
		int overlayH = overlap.bottom - overlap.top;

		//防止红外图完全覆盖可见光图时报错。
		if (overlap.left == 0 && overlap.top == 0){
			overlayW--;
			overlayH--;
		}

		Bitmap newBmp = Bitmap.createBitmap(big,overlap.left,overlap.top,overlayW,overlayH);
		big.recycle();
		
		Canvas canvas = new Canvas(newBmp);
		Paint paint = new Paint();
		paint.setAlpha(alpha);
		canvas.drawBitmap(small, smallX >= 0 ? 0 : smallX, smallY >= 0 ? 0 : smallY, paint);
		small.recycle();
		
		return newBmp;
	}
	
		/**
   * 求矩形的重叠区域
   * @param r1
   * @param r2
   * @return
   */
	public static Rect intersect(Rect r1,Rect r2){
		Rect r = new Rect();
		r.left = Math.max(r1.left, r2.left);
		r.top = Math.max(r1.top, r2.top);
		r.right = Math.min(r1.right, r2.right);
		r.bottom = Math.min(r1.bottom, r2.bottom);
		
		if (r.left > r.right || r.top > r.bottom)
			r = null;
			
		return r;
	}

另一方面,Bitmap在绘制图片时,可以传入四个参数,参数和Rect参数一样,可以只绘制矩形区域大小。

Bitmap newBmp = Bitmap.createBitmap(big,overlap.left,overlap.top,overlayW,overlayH);

根据范围,先绘制可见光图的重叠部分,再绘制红外热图的重叠部分,红外热图设置一下透明度,最后得到融合后的图。

最终效果

  


Demo






评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值