【问题标题】:Copy a bit matrix from bitmap image in ANDROID programming在ANDROID编程中从位图图像复制位矩阵
【发布时间】:2016-11-05 23:31:21
【问题描述】:

我正在开发一个 android 应用程序,它可以帮助用户通过素描或绘图来复制位图的一部分。我的意思是用户将在以位图为背景的画布上绘制一些形状,然后我将点着色为位图(位矩阵/二维位数组)。直到这里,每一次击打听起来都不错。

现在的问题是如何复制在矩阵中具有对应真实位的图像部分?

补充说明

1) 主图:

2) 图片作为画布背景:

3) 画布上的一些画作:

4) 绘制区域的位矩阵表示:

5) 预期输出:

【问题讨论】:

  • 在未设置位的位置应该出现什么?我的意思是什么默认值。
  • @PaulStelian ,它们将是透明的。假设将从图像中删除真实位!
  • 那么你将如何表示这种透明度?你有什么样的输出? PNG?
  • @PaulStelian ,我认为最好的扩展是 PNG!任何想法?但我认为现在没有提及。我想我应该在保存时考虑一下!我是真的吗?
  • PNG 有它自己的透明度,想想。这就是我建议它的原因。但是你需要格式。

标签: android matrix bitmap


【解决方案1】:

你可以这样做。该示例使用Bitmap 作为源,另一个Bitmap 作为过滤矩阵。过滤位图具有透明背景,过滤位图也是如此:

public Bitmap doFilter(Bitmap source, Bitmap filter) {
    Bitmap filtered = Bitmap.createBitmap(source.getWidth(), source.getHeight(), source.getConfig());

    Paint paint = new Paint();
    Canvas canvas = new Canvas(filtered);

    canvas.drawBitmap(source, 0, 0, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    canvas.drawBitmap(filter, 0, 0, paint);

    return filtered;
}

例如,使用此来源:

还有这个过滤器:

你会得到这个过滤后的图像:

【讨论】:

  • 我希望我能把赏金给你和德布!两个答案都很棒。我要测试它们,但我认为虽然 Debu 的答案更详细,但 antonio 的答案会更好。
  • 我已经测试了你的代码,它的效果最好。谢谢。 TG。
【解决方案2】:

根据您给出的解释,我制作了以下示例项目,代码如下 -

public class ActivityImage extends AppCompatActivity{
Button grab;
CustomImageView iv_custom;
ImageView iv_later;
Bitmap bitmapBG,bitmapOrg;
int iMin,jMin,iMax,jMax;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.so_particular_img_section);
    iv_custom = (CustomImageView)findViewById(R.id.iv_custom);
    iv_custom.setDrawingCacheEnabled(true);
    iv_later = (ImageView)findViewById(R.id.iv_later);
    grab = (Button)findViewById(R.id.btn_grab);
    grab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            iv_custom.buildDrawingCache();
            bitmapBG = iv_custom.getDrawingCache();
            getSelectedRegionOnly();
        }
    });
}

/**
 * this method will return the whole image But only the selected region is highlighted and the rest section is simply white
 */
private void getSelectedRegionWithBG(){
    int[] mainImageArray = iv_custom.getImagePixels();
    int[] bgImageArray = new int[bitmapBG.getWidth() * bitmapBG.getHeight()];
    int[] finalImageArray = new int[bitmapBG.getWidth() * bitmapBG.getHeight()];
    bitmapBG.getPixels(bgImageArray,0,bitmapBG.getWidth(), 0, 0, bitmapBG.getWidth(), bitmapBG.getHeight());

    if(mainImageArray.length == bgImageArray.length){
        for(int i = 0; i < (bitmapBG.getWidth() * bitmapBG.getHeight());i++){
            if(mainImageArray[i] == bgImageArray[i]){
                finalImageArray[i] = Color.WHITE;
            }else{
                finalImageArray[i] = mainImageArray[i];
            }
        }

        Bitmap finalBitmap = Bitmap.createBitmap(bitmapBG.getWidth(), bitmapBG.getHeight(), Bitmap.Config.ARGB_8888);
        // Set the pixels
        finalBitmap.setPixels(finalImageArray, 0, finalBitmap.getWidth(), 0, 0, finalBitmap.getWidth(), finalBitmap.getHeight());
        iv_later.setImageBitmap(finalBitmap);
    }else{
        Toast.makeText(ActivityImage.this,"Array length are not same",Toast.LENGTH_SHORT).show();
    }

}

/**
 * This method will select only the selected region from the main image and create the bitmap
 */
private void getSelectedRegionOnly(){
    generateBounds();
    int count = 0;
    int[] finalImageArray = new int[(1+iMax - iMin) * (1+jMax - jMin)];
    Bitmap finalBitmap = Bitmap.createBitmap((1+jMax - jMin), (1+iMax - iMin), Bitmap.Config.ARGB_8888);
        for(int i = iMin; i <= iMax; i++){
            for(int j = jMin; j <= jMax; j++){
                if(bitmapBG.getPixel(j,i) != bitmapOrg.getPixel(j,i)) {
                    finalImageArray[count] = bitmapOrg.getPixel(j, i);
                }else {
                    finalImageArray[count] = Color.WHITE;
                }
                count++;
            }
        }
        // Set the pixels
        finalBitmap.setPixels(finalImageArray, 0, finalBitmap.getWidth(), 0, 0, finalBitmap.getWidth(), finalBitmap.getHeight());
        iv_later.setImageBitmap(finalBitmap);

}

/**
 * generates the bound of the coloured region
 */
private void generateBounds(){
    bitmapOrg = iv_custom.getMainBitmap();
    iMax = jMax = 0;
    iMin = jMin = bitmapBG.getWidth() * bitmapBG.getHeight();
    for(int i = 0; i < bitmapBG.getHeight(); i++){
        for(int j = 0; j < bitmapBG.getWidth(); j++){
            if(bitmapBG.getPixel(j,i) != bitmapOrg.getPixel(j,i)){
                if(iMin > i){
                    iMin = i;
                }
                if(jMin > j){
                    jMin = j;
                }
                if(iMax < i){
                    iMax = i;
                }
                if(jMax < j){
                    jMax = j;
                }
            }
        }
    }
}


}

布局文件-

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="GRAB IMAGE"
    android:id="@+id/btn_grab"
    android:layout_alignParentBottom="true"/>
    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:id="@+id/demo"
    android:orientation="vertical"
    android:layout_above="@id/btn_grab"
    >
    <com.wandertails.stackovrflw.CustomImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/iv_custom"
        android:layout_weight="1" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/iv_later"
        android:layout_weight="1"/>
</LinearLayout>
</RelativeLayout>

终于自定义图片View -

public class CustomImageView extends ImageView {
int width,height;
Bitmap sample;

Context con;
Paint paint=new Paint();
public CustomImageView(Context context) {
    super(context);
    con = context;
}

public CustomImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    con = context;
}

public CustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    con = context;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    sample = createBackground(width,height,con);
    canvas.drawBitmap(sample,0,0,paint);
    canvas.drawBitmap(createForeground(width,height,con),0,0,paint);
    paint.setColor(Color.RED);
    //canvas.drawRect(400,400,600,600,paint);
    //canvas.drawCircle(400,400,200,paint);
}

public int[] getImagePixels(){
    int[] pixels = new int[sample.getWidth() * sample.getHeight()];
    sample.getPixels(pixels, 0, sample.getWidth(), 0, 0, sample.getWidth(), sample.getHeight());
    return pixels;
}

public Bitmap getMainBitmap(){
    return sample;
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    width = w;
    height = h;
}

private Bitmap createBackground(int width, int height, Context con) {
    Bitmap logo = null;
    logo = BitmapFactory.decodeResource(con.getResources(), R.drawable.sample);
    return Bitmap.createScaledBitmap(logo,width,height,true).copy(Bitmap.Config.ARGB_8888,true);
}

private Bitmap createForeground(int width, int height, Context con) {
    Bitmap logo = null;
    logo = BitmapFactory.decodeResource(con.getResources(), R.drawable.sample1);
    return Bitmap.createScaledBitmap(logo,width,height,true).copy(Bitmap.Config.ARGB_8888,true);
}

}

以下是我获得的一些屏幕截图 -

代码可能没有那么优化,但我认为它会达到您的目的。此外,您可以使用任何形状或设计作为遮罩(需要选择的区域),如果您需要任何解释,请询问我..

【讨论】:

  • 我希望我能把赏金给你和安东尼奥!两个答案都很棒。我要测试它们,但我认为虽然 Debu 的答案更详细,但 antonio 的答案会更好。
  • 如果您只需要遮罩,Antonio 的回答显然是正确的,但是我制作了这个示例以便您获得以下好处 - 1. 您不需要任何过滤器位图 2. 在像用户这样的自定义场景中可以选择(例如,用户可以触摸并拖动手指来选择)图像的任何部分,此代码将起作用
  • 3.最后说有一个 200 x 200 的图像,并且用户从右上部分选择了 40 x 40,然后使用 getSelectedRegionOnly() 你可以只获得所选部分的 40 x 40 位图。我不需要赏金,如果我的代码解决了你的问题,那就是我最大的奖励
  • 这句话很棒“如果我的代码解决了你的问题,那就是我最大的回报”。您的代码以自己的方式非常好。但我将使用生成的图片作为未来作品的图层,并且我需要尺寸保持与默认值相同。我不得不说,赏金只是为了感谢你的努力,而不是工作的代价。非常感谢。 TG。
【解决方案3】:

我会有三个位图。第一个是您显示为背景的内容。第二个是用户绘制蒙版的位置,第三个是结果。

显示背景图像并在其上绘制遮罩位图。允许用户在蒙版上绘图。一旦他们对蒙版感到满意,只需遍历像素,当您找到一个不为空的像素时,您就知道这是一个应该被复制的像素。您将从迭代中获得像素位置,因此您可以从背景位图中读取该位置并将该值写入结果位图中。

【讨论】:

  • 你只是把我的解释还给我自己。我需要一些能产生非方形图片的工作代码。
猜你喜欢
  • 1970-01-01
  • 2011-08-31
  • 2017-03-09
  • 2021-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-23
  • 2021-06-05
相关资源
最近更新 更多