前言
- openCV操作像素的方式有十几种,但常用的也就三种,今天就讲解一下三种方式.
1.使用指针(像素数组): 优点是速度快耗时少
2.迭代器 : 优点是不会越界,安全性高
3.动态地址计算 : 优点是理解方式和现实逻辑一样,易于理解
今天通过一个改变图片灰度值的例子,讲解下操作像素的方式
我们知道,java 中图片是ARGB格式表示,但在OpenCV中,图片是以BGRA格式标识,所以我们在使用时需要进行变换.
将ARGB转换为BGRA
Mat img(h, w, CV_8UC4, (unsigned char *) arr);
灰度图 以数组存储每个像素的数据,每个数据叫做一个灰度值
将三个色值都改为 R*0.299+G*0.587+B*0.114 即 彩色转黑白公式
Vec 4 b
向量 4通道 数据类型(b代表uchar)
- 下面是布局文件
- 下面是主界面
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
static {
System.loadLibrary("native-lib");
}
private Button btn_change_gray;
private Bitmap bitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_change_gray = (Button) findViewById(R.id.btn_change_gray);
btn_change_gray.setOnClickListener(this);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ds);
iv.setImageBitmap(bitmap);
}
//改变图片灰度值
public native int[] change_gray(int[] arr, int w, int h);
@Override
public void onClick(View v) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
switch (v.getId()) {
case R.id.btn_change_gray:
int[] p = new int[w * h];
bitmap.getPixels(p, 0, w, 0, 0, w, h);
//调用native方法进行图片处理
int[] result_gray = change_gray(p, w, h);
Bitmap bitmap1 = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
bitmap1.setPixels(result_gray,0,w,0,0,w,h);
iv.setImageBitmap(bitmap1);
break;
}
}
}
- 下面是cpp文件
#include
#include
#include
#include
using namespace cv;
using namespace std;
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_otitan_opencvdemo_MainActivity_change_1gray(JNIEnv *env, jobject jobj, jintArray arr_,
jint w, jint h) {
jint *arr = env->GetIntArrayElements(arr_, NULL);
if (arr == NULL) {
return 0;
}
//将ARGB转换为BGRA
Mat img(h, w, CV_8UC4, (unsigned char *) arr);
//----------------------------------------------------------------------------
//第一种:指针的方式操作像素
//图片起始位置
uchar *ptr = img.ptr(0);
for (int i = 0; i < w * h; i++) {
//R*0.299+G*0.587+B*0.114
uchar GrayPixer = (uchar)(ptr[4 * i + 2] * 0.299 + ptr[4 *i + 1] * 0.587 + ptr[4 *i + 0] * 0.114);
ptr[4 * i + 0] = GrayPixer;
ptr[4 * i + 1] = GrayPixer;
ptr[4 * i + 2] = GrayPixer;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//第二种:迭代器方式
Mat_::iterator it = img.begin();
Mat_::iterator itend = img.end();
while (it != itend) {
uchar temp = (*it)[2] * 0.299 + (*it)[1] * 0.587 + (*it)[0] * 0.114;
(*it)[2] = temp;
(*it)[1] = temp;
(*it)[0] = temp;
it++;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//第三种:动态地址计算
int a = img.rows;//行
int b = img.cols;//列
for (int i = 0; i < a; ++i) {
for (int j = 0; j < b; ++j) {
uchar temp = img.at(i, j)[2] * 0.229 +
img.at(i, j)[1] * 0.587 +
img.at(i, j)[0] * 0.114;
img.at(i, j)[2] = temp;
img.at(i, j)[1] = temp;
img.at(i, j)[0] = temp;
}
}
//----------------------------------------------------------------------------
int size = w * h;
jintArray resultArray = env->NewIntArray(size);
env->SetIntArrayRegion(resultArray, 0, size, arr);
env->ReleaseIntArrayElements(arr_, arr, 0);
return resultArray;
}
- 图片处理结果