OpenCV Android簡單處理
文章目錄
- OpenCV Android簡單處理
- 前言
- 一、Android Studio 引入opencv
- 二、opencv初始化
- 三、圖片處理相關內容及代碼
- 1. 圖片亮白處理
- 2. 圖片飽和度內容處理
- 3. 圖片自然顯示處理
- 4. 圖片清晰處理
- 5. CmnUtils代碼如下
- 總結
前言
由于專案中需要進行圖片美顏相關處理,因此看了下opencv,實作還是很簡單的,直接看相關內容,但存在打包出的app過大的問題,因此又參考相關實作演算法,整了一套對應的bitmap處理方案,
一、Android Studio 引入opencv
app的build.gradle的引入方式如下,這里使用的是opencv 4.5.3版本:
implementation 'com.quickbirdstudios:opencv:4.5.3.0'
二、opencv初始化
使用opencv之前需要先初始化一下
/**
* bInitOpenCV 是否已經初始化opencv
*/
public static boolean bInitOpenCV = false;
/**
* initOpenCV 初始化opencv
*/
private static boolean initOpenCV() {
if (bInitOpenCV)
return true;
boolean bStatus = OpenCVLoader.initDebug();
if (bStatus)
bInitOpenCV = true;
return bInitOpenCV;
}
三、圖片處理相關內容及代碼
1. 圖片亮白處理
opencv代碼如下:
/**
* whiteDeal opencv的圖片美白顯示處理
* @param src 輸入源bitmap
* @param nFactor 影響因子
* @return bitmap 回傳對應的bitmap結果
*/
public static Bitmap whiteDeal(Bitmap src, int nFactor) {
if (!initOpenCV())
return null;
Mat img = new Mat(src.getHeight(), src.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(src, img);
int channels = img.channels();
int width = img.width();
int height = img.height();
// 影像自然度開始處理
byte[] bytes = new byte[channels];
int b, g, r;
int b_new, g_new, r_new;
for (int row = 0; row < height; ++row)
{
for (int col = 0; col < width; ++col)
{
img.get(row, col, bytes);
b = bytes[0] & 0xff;
g = bytes[1] & 0xff;
r = bytes[2] & 0xff;
r_new = CmnUtils.getLimitValue(r + nFactor);
g_new = CmnUtils.getLimitValue(g + nFactor);
b_new = CmnUtils.getLimitValue(b + nFactor);
bytes[0] = (byte)b_new;
bytes[1] = (byte)g_new;
bytes[2] = (byte)r_new;
img.put(row, col, bytes);
}
}
// 影像自然度結束處理
Bitmap newValue = Bitmap.createBitmap(img.cols(), img.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(img, newValue);
return newValue;
}
bitmap代碼如下:
/**
* whiteDeal bitmap的圖片美白顯示處理
* @param src 輸入的bitmap源
* @param nFactor 影響因子
* @return bitmap 輸出的bitmap
*/
public static Bitmap whiteDeal(Bitmap src, int nFactor) {
int width = src.getWidth();
int height = src.getHeight();
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
//
int A, R, G, B;
int pixel;
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
pixel = src.getPixel(x, y);
A = Color.alpha(pixel);
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
// in
R = CmnUtils.getLimitValue(R + nFactor);
G = CmnUtils.getLimitValue(G + nFactor);
B = CmnUtils.getLimitValue(B + nFactor);
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
return bmOut;
}
2. 圖片飽和度內容處理
opencv代碼如下:
/**
* VibranceAlgorithm opencv飽和度顯示處理
* @param src 輸入源bitmap
* @param nFactor 影響因子
* @return bitmap 回傳對應的bitmap結果
*/
public static Bitmap VibranceAlgorithm(Bitmap src, int nFactor) {
if (!initOpenCV())
return null;
Mat img = new Mat(src.getHeight(), src.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(src, img);
nFactor += 65; // +50為了初始圖片
int channels = img.channels();
int width = img.width();
int height = img.height();
// 影像飽和度開始處理
float fIncrement = (float)((nFactor - 80) * 1.0 / CmnUtils.max_Increment);
byte[] bytes = new byte[channels];
int b = 0, g = 0, r = 0;
int b_new, g_new, r_new;
for (int row = 0; row < height; ++row)
{
for (int col = 0; col < width; ++col)
{
img.get(row, col, bytes);
b = bytes[0] & 0xff;
g = bytes[1] & 0xff;
r = bytes[2] & 0xff;
// 處理
int nMax = Math.max(Math.max(b, g), r);
int nMin = Math.min(Math.min(b, g), r);
float delta, value;
float L, S, alpha;
delta = (float)((nMax - nMin) / 255.0);
if (delta == 0)
continue;
value = (float)((nMax + nMin) / 255.0);
L = value / 2;
if (L < 0.5)
S = delta / value;
else
S = delta / (2 - value);
if (fIncrement >= 0)
{
if ((fIncrement + S) >= 1)
alpha = S;
else
alpha = 1 - fIncrement;
alpha = 1 / alpha - 1;
r_new = CmnUtils.getLimitValue((int)(r + (r - L * 255) * alpha));
g_new = CmnUtils.getLimitValue((int)(g + (g - L * 255) * alpha));
b_new = CmnUtils.getLimitValue((int)(b + (b - L * 255) * alpha));
} else {
alpha = fIncrement;
r_new = CmnUtils.getLimitValue((int)(L * 255 + (r - L * 255) * (1 + alpha)));
g_new = CmnUtils.getLimitValue((int)(L * 255 + (g - L * 255) * (1 + alpha)));
b_new = CmnUtils.getLimitValue((int)(L * 255 + (b - L * 255) * (1 + alpha)));
}
bytes[0] = (byte)b_new;
bytes[1] = (byte)g_new;
bytes[2] = (byte)r_new;
img.put(row, col, bytes);
}
}
// 影像飽和度結束處理
Bitmap newValue = Bitmap.createBitmap(img.cols(), img.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(img, newValue);
return newValue;
}
bitmap代碼如下:
/**
* VibranceAlgorithm bitmap的飽和度內容處理
* @param src 輸入源bitmap
* @param nFactor 影響因子
* @return bitmap 回傳對應的bitmap結果
*/
public static Bitmap VibranceAlgorithm(Bitmap src, int nFactor) {
int width = src.getWidth();
int height = src.getHeight();
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
int pixel;
nFactor += 100;
// 影像飽和度開始處理
float fIncrement = (float)((nFactor - 80) * 1.0 / CmnUtils.max_Increment);
int a, b, g, r;
int b_new, g_new, r_new;
for (int y = 0; y < width; ++y) {
for (int x = 0; x < height; ++x) {
pixel = src.getPixel(y, x);
a = Color.alpha(pixel);
r = Color.red(pixel);
g = Color.green(pixel);
b = Color.blue(pixel);
int nMax = Math.max(Math.max(b, g), r);
int nMin = Math.min(Math.min(b, g), r);
float delta, value;
float L, S, alpha;
delta = (float)((nMax - nMin) / 255.0);
if (delta == 0) {
r_new = r;
g_new = g;
b_new = b;
} else {
value = (float) ((nMax + nMin) / 255.0);
L = value / 2;
if (L < 0.5)
S = delta / value;
else
S = delta / (2 - value);
if (fIncrement >= 0) {
if ((fIncrement + S) >= 1)
alpha = S;
else
alpha = 1 - fIncrement;
alpha = 1 / alpha - 1;
r_new = CmnUtils.getLimitValue((int) (r + (r - L * 255) * alpha));
g_new = CmnUtils.getLimitValue((int) (g + (g - L * 255) * alpha));
b_new = CmnUtils.getLimitValue((int) (b + (b - L * 255) * alpha));
} else {
alpha = fIncrement;
r_new = CmnUtils.getLimitValue((int) (L * 255 + (r - L * 255) * (1 + alpha)));
g_new = CmnUtils.getLimitValue((int) (L * 255 + (g - L * 255) * (1 + alpha)));
b_new = CmnUtils.getLimitValue((int) (L * 255 + (b - L * 255) * (1 + alpha)));
}
}
bmOut.setPixel(y, x, Color.argb(a, r_new, g_new, b_new));
}
}
// 影像飽和度結束處理
return bmOut;
}
3. 圖片自然顯示處理
opencv代碼如下:
/**
* contrastBright opencv的圖片自然顯示處理
* @param src 輸入源bitmap
* @param nFactor 影響因子
* @return bitmap 回傳對應的bitmap結果
*/
public static Bitmap contrastBright(Bitmap src, int nFactor) {
if (!initOpenCV())
return null;
Mat img = new Mat(src.getHeight(), src.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(src, img);
nFactor += 18; // +18是為了影像和初始圖片比較相似
int channels = img.channels();
int width = img.width();
int height = img.height();
// 影像自然度開始處理
// 對比度 = 亮度 / 1.5;
int contrastValue = nFactor / 2;
float fContrastValue = (float)(0.1 * contrastValue);
byte[] bytes = new byte[channels];
int b = 0, g = 0, r = 0;
int b_new, g_new, r_new;
for (int row = 0; row < height; ++row)
{
for (int col = 0; col < width; ++col)
{
img.get(row, col, bytes);
b = bytes[0] & 0xff;
g = bytes[1] & 0xff;
r = bytes[2] & 0xff;
r_new = CmnUtils.getLimitValue((int)(fContrastValue * r + nFactor));
g_new = CmnUtils.getLimitValue((int)(fContrastValue * g + nFactor));
b_new = CmnUtils.getLimitValue((int)(fContrastValue * b + nFactor));
bytes[0] = (byte)b_new;
bytes[1] = (byte)g_new;
bytes[2] = (byte)r_new;
img.put(row, col, bytes);
}
}
// 影像自然度結束處理
Bitmap newValue = Bitmap.createBitmap(img.cols(), img.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(img, newValue);
return newValue;
}
bitmap代碼如下:
/**
* contrastBright bitmap的圖片自然顯示處理
* @param src 輸入源bitmap
* @param nFactor 影響因子
* @return bitmap 回傳對應的bitmap結果
*/
public static Bitmap contrastBright(Bitmap src, int nFactor) {
nFactor += 18; // +18是為了影像和初始圖片比較相似
int width = src.getWidth();
int height = src.getHeight();
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
// 影像自然度開始處理
// 對比度 = 亮度 / 1.5;
int contrastValue = nFactor / 2;
float fContrastValue = (float)(0.1 * contrastValue);
int pixel;
int a, b, g, r;
int b_new, g_new, r_new;
for (int x = 0; x < height; ++x) {
for (int y = 0; y < width; ++y) {
pixel = src.getPixel(y, x);
a = Color.alpha(pixel);
r = Color.red(pixel) & 0xFF;
g = Color.green(pixel) & 0xFF;
b = Color.blue(pixel) & 0xFF;
r_new = CmnUtils.getLimitValue((int)(fContrastValue * r + nFactor));
g_new = CmnUtils.getLimitValue((int)(fContrastValue * g + nFactor));
b_new = CmnUtils.getLimitValue((int)(fContrastValue * b + nFactor));
bmOut.setPixel(y, x, Color.argb(a, r_new, g_new, b_new));
}
}
// 影像自然度結束處理
return bmOut;
}
4. 圖片清晰處理
opencv代碼如下:
/**
* usmDeal opencv圖片清晰顯示處理
* @param src 輸入源bitmap
* @param fFactor 影響因子
* @return bitmap 回傳對應的bitmap結果
*/
public static Bitmap usmDeal(Bitmap src, float fFactor) {
if (!initOpenCV())
return null;
Mat img = new Mat(src.getHeight(), src.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(src, img);
// 影像清晰度開始處理
Mat blurMask = new Mat();
// 高斯模糊
Imgproc.GaussianBlur(img, blurMask, new Size(3, 3), 3, 3);
// 圖片疊加
Core.addWeighted(img, 1 + fFactor, blurMask, -fFactor, 0, img);
// 影像清晰度結束處理
Bitmap newValue = Bitmap.createBitmap(img.cols(), img.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(img, newValue);
return newValue;
}
bitmap代碼如下:
/**
* usmDeal bitmap的圖片清晰顯示處理
* @param context 背景關系
* @param src 輸入源bitmap
* @param fFactor 影響因子
* @return bitmap 回傳對應的bitmap結果
*/
public static Bitmap usmDeal(Context context, Bitmap src, float fFactor) {
// 影像清晰度開始處理
// 高斯模糊
Bitmap bitBlur = CmnUtils.gaussBlur(context, src, 1.1f);
return CmnUtils.addWeighted(src, 1 + fFactor, bitBlur, -fFactor, 0);
// 影像清晰度結束處理;
}
5. CmnUtils代碼如下
/**
* CmnUtils 圖片處理通用處理方法
*/
public class CmnUtils {
//
public final static int max_Increment = 200;
/**
* getLimitValue 獲取指定范圍內的值
* @param value 傳入值
* @return 對應的限定值
*/
public static int getLimitValue(int value) {
if (value > 255)
value = 255;
else if (value < 0)
value = 0;
return value;
}
/**
* gaussBlur 高斯模糊處理
* @param context 背景關系
* @param bitmap 輸入的bitmap
* @param radius 對應的高斯模糊半徑
*/
public static Bitmap gaussBlur(Context context, Bitmap bitmap, float radius) {
// 創建輸出圖片
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
// 創建輸出圖片
RenderScript rs = RenderScript.create(context);
// 創建高斯模糊腳本
ScriptIntrinsicBlur gaussianBlur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
// 創建用于輸入的腳本型別
Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
// 創建用于輸出的腳本型別
Allocation allOut = Allocation.createFromBitmap(rs, output);
// 設定模糊半徑,范圍0f<radius<=25f
gaussianBlur.setRadius(radius);
// 設定輸入腳本型別
gaussianBlur.setInput(allIn);
// 執行高斯模糊演算法,并將結果填入輸出腳本型別中
gaussianBlur.forEach(allOut);
// 將輸出記憶體編碼為Bitmap,圖片大小必須注意
allOut.copyTo(output);
// 關閉RenderScript物件,API>=23則使用rs.releaseAllContexts()
rs.destroy();
return output;
}
/**
* addWeighted 把兩張相同尺寸的圖片合并到一起
* @param first 輸入圖片1
* @param alpha 圖片1的融合比例
* @param second 輸入圖片2
* @param beta 圖片2的融合比例
* @param gamma 偏差
* @return bitmap 回傳對應的bitmap結果
*/
public static Bitmap addWeighted(Bitmap first, float alpha, Bitmap second, float beta, double gamma) {
int width = first.getWidth();
int height = first.getHeight();
Bitmap bmOut = Bitmap.createBitmap(width, height, first.getConfig());
if (width != second.getWidth() || height != second.getHeight())
return bmOut;
int pixel1, pixel2;
int a, b1, g1, r1;
int b2, g2, r2;
int b_new, g_new, r_new;
for (int x = 0; x < height; ++x) {
for (int y = 0; y < width; ++y) {
pixel1 = first.getPixel(y, x);
a = Color.alpha(pixel1);
r1 = Color.red(pixel1);
g1 = Color.green(pixel1);
b1 = Color.blue(pixel1);
pixel2 = second.getPixel(y, x);
r2 = Color.red(pixel2);
g2 = Color.green(pixel2);
b2 = Color.blue(pixel2);
b_new = CmnUtils.getLimitValue((int)(b1 * alpha + b2 * beta + gamma));
g_new = CmnUtils.getLimitValue((int)(g1 * alpha + g2 * beta + gamma));
r_new = CmnUtils.getLimitValue((int)(r1 * alpha + r2 * beta + gamma));
bmOut.setPixel(y, x, Color.argb(a, r_new, g_new, b_new));
}
}
return bmOut;
}
}
總結
opencv使用時,需要先初始化一下,以上代碼已經很詳細了,目前只是簡單的使用,后面涉及人臉識別之類的,就需要匯入對應的人臉識別庫檔案,目前存在的問題主要有兩個:
- 處理的效果差強人意
- 處理效率非常差
但就測驗而言,opencv的效率普遍沒有bitmap的處理速度快,應該是opencv沒有使用硬體加速(GPU)導致的,
最后附上原始碼,有需要的可以自己看下
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/384434.html
標籤:其他
下一篇:聊聊讓開發頭疼的一句話需求那些事
