How to use GPUImage in Android Part-2

Before we proceed, you must be cleared with Part-1. Now let us see the demo project on how to use GPUImage in Android? In this demo we will learn how to apply filter and contrast to any image.

Procedure:

a. Let’s create an activity “ChooseImage” by right clicking on package New ? Activity ? Empty Activity. ChooseImage activity will help you to select image from phone gallery. Keep this activity as launcher activity. Now past the below code in your xml file. This xml file consists of button element.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:gravity="center"
tools:context="com.android.gpuimagedemo.ChooseImage">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Choose Image"
android:id="@+id/btn_choose_img"/>
</LinearLayout>

b. Paste the below code in your ChooseImage.java file. When onClick() method of button is fired, then user is redirected to phone gallery to select image. OnActivityResult() method will return the selected image data and then passed to the another activity.

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class ChooseImage extends AppCompatActivity implements View.OnClickListener{
private Button btn_choose_image;
private static final int REQUEST_PICK_IMAGE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_choose_image);
btn_choose_image=(Button)findViewById(R.id.btn_choose_img);
btn_choose_image.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.equals(btn_choose_image))
{
//Choose image from gallery.
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, REQUEST_PICK_IMAGE);
}
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_PICK_IMAGE:
if (resultCode == RESULT_OK) {
Intent intent=new Intent(getApplicationContext(),MainActivity.class);
intent.putExtra("image_path",String.valueOf(data.getData()));
startActivity(intent);
Log.i("Image Gallery",""+data.getData());
} else {
finish();
}
break;
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
}

c. Create another activity named “MainActivity” by right clicking on package New ? Activity ? Empty Activity. In your activity_main.xml add the GPUImageView. GPUImageView is a type of ImagvView which is different from Android by default ImageView. In order to use GPUImageView, you have to add “jp.co.cyberagent.android.gpuimage.GPUImageView” as a element in your layout.

<jp.co.cyberagent.android.gpuimage.GPUImageView
android:id="@+id/gpuimage"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

d. Paste the below code into your activity_main.xml file. This xml file consists of GPUImageView, Seekbar and two buttons. Seekbar will be used for adjusting the contrast level.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.android.gpuimagedemo.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="80">
<jp.co.cyberagent.android.gpuimage.GPUImageView
android:id="@+id/gpuimage"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_weight="10">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Apply Filter"
android:layout_gravity="center"
android:id="@+id/apply_filter"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Apply Contrast"
android:layout_gravity="center"
android:id="@+id/apply_contrast"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_weight="10">
<SeekBar
android:id="@+id/adjustment_seekBar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="15"
android:layout_gravity="center"
android:visibility="gone"
android:max="100" />
</LinearLayout>
</LinearLayout>

e. Now in MainActivity.java initialize all the elements used in layout. Implement MainActivity.java with View.OnClickListener and SeekBar.OnSeekBarChangeListener.

import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import java.util.ArrayList;
import java.util.Random;
import jp.co.cyberagent.android.gpuimage.GPUImage;
import jp.co.cyberagent.android.gpuimage.GPUImageContrastFilter;
import jp.co.cyberagent.android.gpuimage.GPUImageLookupFilter;
import jp.co.cyberagent.android.gpuimage.GPUImageView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener,SeekBar.OnSeekBarChangeListener{
private GPUImageView gpuImageView;
private String image_path; //Path of selected image from gallery
private Button btn_apply_filter,btn_apply_contrast;
private SeekBar seekBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Receiving Uri of selected image from ChooseImage Activity.
final Bundle bundle=getIntent().getExtras();
image_path=bundle.getString("image_path");
//Initializing the GPUImageVIew
gpuImageView=(GPUImageView)findViewById(R.id.gpuimage);
//Initializing the Button
btn_apply_filter=(Button)findViewById(R.id.apply_filter);
btn_apply_filter.setOnClickListener(this);
btn_apply_contrast=(Button)findViewById(R.id.apply_contrast);
btn_apply_contrast.setOnClickListener(this);
seekBar=(SeekBar)findViewById(R.id.adjustment_seekBar);
seekBar.setOnSeekBarChangeListener(this);
gpuImageView.setScaleType(GPUImage.ScaleType.CENTER_INSIDE);
}
@Override
public void onClick(View v) {
if (v.equals(btn_apply_filter))
{
}
else if(v.equals(btn_apply_contrast))
{
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}

f. Now add the below method to MainActivity.java. Method will help to find the aspect ratio accordingly to the height and width of the selected image. Set this ratio value to gpuImageView. If ratio to gpuImageView is not used, the filter or the contrast will be applied to the whole GPUImage area instead to be applied in the select image area.

private float getAspectRatio(Uri uri){
int imageHeight,imageWidth;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(getPath(uri), options);
imageHeight = options.outHeight;
imageWidth = options.outWidth;
gpuImageView.setMinimumWidth(imageWidth);
gpuImageView.setMinimumHeight(imageHeight);
float ratio=((float)imageWidth/(float)imageHeight);
return ratio;
}

g. Add the below method to MainActivity.java in order to get the path of the selected image.

public String getPath(Uri uri) {
// just some safety built in
if( uri == null ) {
// TODO perform some logging or show user feedback
return null;
}
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if( cursor != null ){
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
// this is our fallback here
return uri.getPath();
}

h. Now initialize the GPUImageLookupFilter and List<GPUImageLookupFilter> as a global variable and add the getFilter() method to MainActivity.java. “GPUImageLookupFilter” is a class in GPUImage library. GPUImageLookupFilte.java consists of shader writen in OpenGL language. You can modify according to your requirement.

private void getFilters()
{
filter1=new GPUImageLookupFilter();
filter1.setBitmap(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.cl));
filter2=new GPUImageLookupFilter();
filter2.setBitmap(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.cm));
lookupFilterList.add(filter1);
lookupFilterList.add(filter2);
}

i. Add below method for switching the filters in your MainActivity.java. While setting any filter to GPUImageView, requestRender() method of GPUImage must be called in order to render the effect to the image. This method is used for applying the filters to image.

private void switchFilter(GPUImageLookupFilter filter)
{
mFilter=filter;
//Setting filters to GPUImageView
gpuImageView.setFilter(mFilter);
gpuImageView.requestRender();
}

j. Now add the below code inside the onProgressChanged. GPUImageContrastFilter.java is a class written for adjusting the contrast value of any image. When progress bar value is changed the value of contrast will also be changed.

GPUImageContrastFilter gpuImageContrastFilter=new GPUImageContrastFilter();
gpuImageContrastFilter.setContrast(range(progress,0.45f, 1.45f));
gpuImageView.setFilter(gpuImageContrastFilter);
gpuImageView.requestRender();

k. Add the below method in your MainActivity.java to calculate the range.

protected float range(final int percentage, final float start, final float end)
{
return (end - start) * percentage / 100.0f + start;
}

l. Here is the complete code of MainActivity.java

import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import java.util.ArrayList;
import java.util.Random;
import jp.co.cyberagent.android.gpuimage.GPUImage;
import jp.co.cyberagent.android.gpuimage.GPUImageContrastFilter;
import jp.co.cyberagent.android.gpuimage.GPUImageLookupFilter;
import jp.co.cyberagent.android.gpuimage.GPUImageView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener,SeekBar.OnSeekBarChangeListener{
private GPUImageView gpuImageView;
private String image_path; //Path of selected image from gallery
private float ratio;
private Button btn_apply_filter,btn_apply_contrast;
private GPUImageLookupFilter filter1,filter2;
private ArrayList<GPUImageLookupFilter> lookupFilterList;
private GPUImageLookupFilter mFilter;
private SeekBar seekBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Receiving Uri of selected image from ChooseImage Activity.
final Bundle bundle=getIntent().getExtras();
image_path=bundle.getString("image_path");
//Initializing the GPUImageVIew
gpuImageView=(GPUImageView)findViewById(R.id.gpuimage);
//Initializing the Button
btn_apply_filter=(Button)findViewById(R.id.apply_filter);
btn_apply_filter.setOnClickListener(this);
btn_apply_contrast=(Button)findViewById(R.id.apply_contrast);
btn_apply_contrast.setOnClickListener(this);
seekBar=(SeekBar)findViewById(R.id.adjustment_seekBar);
seekBar.setOnSeekBarChangeListener(this);
gpuImageView.setScaleType(GPUImage.ScaleType.CENTER_INSIDE);
ratio=getAspectRatio(Uri.parse(image_path));
//Applying Ratio to GPUImageView
gpuImageView.setRatio(ratio);
//Setting Image to GPUImageView
gpuImageView.setImage(Uri.parse(image_path));
lookupFilterList=new ArrayList<>();
getFilters();
}
//Method to get Aspect Ratio according to the Image height & width
private float getAspectRatio(Uri uri){
int imageHeight,imageWidth;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(getPath(uri), options);
imageHeight = options.outHeight;
imageWidth = options.outWidth;
gpuImageView.setMinimumWidth(imageWidth);
gpuImageView.setMinimumHeight(imageHeight);
float ratio=((float)imageWidth/(float)imageHeight);
return ratio;
}
// To get the absolute path of the image selected
public String getPath(Uri uri) {
// just some safety built in
if( uri == null ) {
// TODO perform some logging or show user feedback
return null;
}
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if( cursor != null ){
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
// this is our fallback here
return uri.getPath();
}
@Override
public void onClick(View v) {
if (v.equals(btn_apply_filter))
{
if (seekBar.getVisibility()==View.VISIBLE)
{
seekBar.setVisibility(View.GONE);
}
//Generating Random Numbers
Random random_num=new Random();
int random_filter=random_num.nextInt(lookupFilterList.size());
switchFilter(lookupFilterList.get(random_filter));
}
else if(v.equals(btn_apply_contrast))
{
seekBar.setVisibility(View.VISIBLE);
}
}
//Method to switch filters
private void switchFilter(GPUImageLookupFilter filter)
{
mFilter=filter;
//Setting filters to GPUImageView
gpuImageView.setFilter(mFilter);
gpuImageView.requestRender();
}
//Initializing all LookUp Filter
private void getFilters()
{
filter1=new GPUImageLookupFilter();
filter1.setBitmap(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.cl));
filter2=new GPUImageLookupFilter();
filter2.setBitmap(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.cm));
lookupFilterList.add(filter1);
lookupFilterList.add(filter2);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
GPUImageContrastFilter gpuImageContrastFilter=new GPUImageContrastFilter();
gpuImageContrastFilter.setContrast(range(progress,0.45f, 1.45f));
gpuImageView.setFilter(gpuImageContrastFilter);
gpuImageView.requestRender();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
//Calculate the range of contrast filter. Set start and end value of contrast filter.
protected float range(final int percentage, final float start, final float end) {
return (end - start) * percentage / 100.0f + start;
}
}

m. Add the below line to AndroidManifest.xml to get the gallery images.


<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

1234

 

Recent Posts

Leave a Comment

Contact Us

We're not around right now. But you can send us an email and we'll get back to you, asap.

Not readable? Change text. captcha txt