• Android处理Bitmap的一些方法


    http://www.it165.net/pro/html/201305/5795.html

    # 文件与Bitmap间的方法


    1. 从文件载入Bitmap

    01./**
    02.* @brief 从文件载入Bitmap
    03.* @param path 图片路径
    04.* @param opts 选项
    05.* @return Bitmap
    06.*/
    07.public Bitmap loadFromFile(String path, Options opts) {
    08.try {
    09.File f = new File(path);
    10.if (!f.exists() || f.isDirectory()) {
    11.return null;
    12.}
    13.Bitmap bm = BitmapFactory.decodeFile(path, opts);
    14.return bm;
    15.catch (Exception e) {
    16.return null;
    17.}
    18.}
    19./**
    20.* @brief 从文件载入Bitmap
    21.* @param path 图片路径
    22.* @return Bitmap
    23.*/
    24.public Bitmap loadFromFile(String path) {
    25.return loadFromFile(path, null);
    26.}

    2. 载入取样的Bitmap


    原宽度和高度的各1/sampleSize大小。


    显示图片文件时一般都是取样图,否则很容易outofmemory。


     

    01./**
    02.* @brief 从文件载入采样后的Bitmap
    03.* @see android.graphics.BitmapFactory.Options#inSampleSize
    04.*/
    05.public Bitmap loadSampleSize(String path, int sampleSize) {
    06.Options opts = new Options();
    07.opts.inSampleSize = sampleSize;
    08.return loadFromFile(path, opts);
    09.}

    3. 载入Bitmap边框


    其返回Bitmap为null,但Options.outxxx会被填充值。包括outHeight, outWidth, outMimeType。


    只读取其高宽信息的话,就不需要读取全部Bitmap了。可结合上个方法,获取倍数缩小的样图。

    01./**
    02.* @brief 从文件载入只获边框的Bitmap www.it165.net
    03.* @see android.graphics.BitmapFactory.Options#inJustDecodeBounds
    04.*/
    05.public Options loadJustDecodeBounds(String path) {
    06.Options opts = new Options();
    07.opts.inJustDecodeBounds = true;
    08.loadFromFile(path, opts);
    09.return opts;
    10.}

    4. 保存Bitmap至文件

     

    01./**
    02.* @brief 保存Bitmap至文件
    03.* @param bm Bitmap
    04.* @param path 图片路径
    05.* @return 成功与否
    06.*/
    07.public boolean compressBitmap(Bitmap bm, String path) {
    08.FileOutputStream out = null;
    09.try {
    10.out = new FileOutputStream(path);
    11.bm.compress(Bitmap.CompressFormat.JPEG, 100, out);
    12.out.flush();
    13.catch (Exception e) {
    14.return false;
    15.} finally {
    16.try {
    17.if (out != null) {
    18.out.close();
    19.}
    20.catch (IOException e) {
    21.}
    22.}
    23.return true;
    24.}

    5. 读取图片方向信息


    Bitmap图片的方法==!!!

    01./**
    02.* @brief 读取图片方向信息
    03.* @param path 图片路径
    04.* @return 角度
    05.*/
    06.public int readPhotoDegree(String path) {
    07.int degree = 0;
    08.try {
    09.ExifInterface exifInterface = new ExifInterface(path);
    10.int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
    11.ExifInterface.ORIENTATION_NORMAL);
    12.switch (orientation) {
    13.case ExifInterface.ORIENTATION_ROTATE_90:
    14.degree = 90;
    15.break;
    16.case ExifInterface.ORIENTATION_ROTATE_180:
    17.degree = 180;
    18.break;
    19.case ExifInterface.ORIENTATION_ROTATE_270:
    20.degree = 270;
    21.break;
    22.default:
    23.degree = 0;
    24.}
    25.catch (IOException e) {
    26.e.printStackTrace();
    27.}
    28.return degree;
    29.}

    # 处理Bitmap的方法

    1. 生成缩略图

    1.public Bitmap extractThumbnail(Bitmap src, int width, int height) {
    2.return ThumbnailUtils.extractThumbnail(src, width, height,
    3.ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
    4.}


    2. 缩放

    01./**
    02.* @brief 缩放Bitmap,自动回收原Bitmap
    03.* @see ImageUtil#scaleBitmap(Bitmap, int, int, boolean)
    04.*/
    05.public Bitmap scaleBitmap(Bitmap src, int dstWidth, int dstHeight) {
    06.return scaleBitmap(src, dstWidth, dstHeight, true);
    07.}
    08./**
    09.* @brief 缩放Bitmap
    10.* @param src 源Bitmap
    11.* @param dstWidth 目标宽度
    12.* @param dstHeight 目标高度
    13.* @param isRecycle 是否回收原图像
    14.* @return Bitmap
    15.*/
    16.public Bitmap scaleBitmap(Bitmap src, int dstWidth, int dstHeight, boolean isRecycle) {
    17.if (src.getWidth() == dstWidth && src.getHeight() == dstHeight) {
    18.return src;
    19.}
    20.Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
    21.if (isRecycle && dst != src) {
    22.src.recycle();
    23.}
    24.return dst;
    25.}

    3. 裁剪

     

    01./**
    02.* @brief 裁剪Bitmap,自动回收原Bitmap
    03.* @see ImageUtil#cropBitmap(Bitmap, int, int, int, int, boolean)
    04.*/
    05.public Bitmap cropBitmap(Bitmap src, int x, int y, int width, int height) {
    06.return cropBitmap(src, x, y, width, height, true);
    07.}
    08./**
    09.* @brief 裁剪Bitmap
    10.* @param src 源Bitmap
    11.* @param x 开始x坐标
    12.* @param y 开始y坐标
    13.* @param width 截取宽度
    14.* @param height 截取高度
    15.* @param isRecycle 是否回收原图像
    16.* @return Bitmap
    17.*/
    18.public Bitmap cropBitmap(Bitmap src, int x, int y, int width, int height, boolean isRecycle) {
    19.if (x == 0 && y == 0 && width == src.getWidth() && height == src.getHeight()) {
    20.return src;
    21.}
    22.Bitmap dst = Bitmap.createBitmap(src, x, y, width, height);
    23.if (isRecycle && dst != src) {
    24.src.recycle();
    25.}
    26.return dst;
    27.}

    4. 旋转

     

    01./**
    02.* @brief 旋转Bitmap,自动回收原Bitmap
    03.* @see ImageUtil#rotateBitmap(Bitmap, int, boolean)
    04.*/
    05.public Bitmap rotateBitmap(Bitmap src, int degree) {
    06.return rotateBitmap(src, degree, true);
    07.}
    08./**
    09.* @brief 旋转Bitmap,顺时针
    10.* @param src 源Bitmap
    11.* @param degree 旋转角度
    12.* @param isRecycle 是否回收原图像
    13.* @return Bitmap
    14.*/
    15.public Bitmap rotateBitmap(Bitmap src, int degree, boolean isRecycle) {
    16.if (degree % 360 == 0) {
    17.return src;
    18.}
    19.int w = src.getWidth();
    20.int h = src.getHeight();
    21.Matrix matrix = new Matrix();
    22.matrix.postRotate(degree);
    23.Bitmap dst = Bitmap.createBitmap(src, 0, 0, w, h, matrix, true);
    24.if (isRecycle && dst != src) {
    25.src.recycle();
    26.}
    27.return dst;
    28.}

    # OpenCV处理Bitmap的方法


    除了导入OpenCV的jar包,我们只需要libopencv_java.so,就可以下做进行操作了。


    1. 常规性的init

    1.static {
    2.if (!OpenCVLoader.initDebug()) {
    3.Log.e(TAG, "OpenCVLoader initDebug failed.");
    4.}
    5.}

    2. 常规性处理流程


    bmp -> mat -> 接口处理 -> mat_new -> bmp_new。

    01.private interface IHandler {
    02.Mat proc(Mat mat_bmp);
    03.}
    04.private Bitmap handle(Bitmap src, IHandler handler) {
    05.Mat mat_bmp = new Mat(src.getHeight(), src.getWidth(), CvType.CV_8UC4);
    06.Utils.bitmapToMat(src, mat_bmp, false); // Bitmap->Mat
    07.Mat mat_new = handler.proc(mat_bmp); // handle mat
    08.Bitmap bmp_new = Bitmap.createBitmap(mat_new.cols(), mat_new.rows(),
    09.Bitmap.Config.ARGB_8888);
    10.Utils.matToBitmap(mat_new, bmp_new, false); // Mat->Bitmap
    11.src.recycle();
    12.return bmp_new;
    13.}

    3. 缩放

     

    01./**
    02.* @brief 缩放Bitmap
    03.* @param src 源Bitmap
    04.* @param dstWidth 目标宽度
    05.* @param dstHeight 目标高度
    06.* @return Bitmap
    07.*/
    08.public Bitmap scaleBitmap2(Bitmap src, final int dstWidth, final int dstHeight) {
    09.if (src.getWidth() == dstWidth && src.getHeight() == dstHeight) {
    10.return src;
    11.}
    12.return handle(src, new IHandler() {
    13.@Override
    14.public Mat proc(Mat mat_bmp) {
    15.Mat mat_new = new Mat();
    16.Imgproc.resize(mat_bmp, mat_new, new Size(dstWidth, dstHeight));
    17.return mat_new;
    18.}
    19.});
    20.}

    4. 裁剪

     

    01./**
    02.* @brief 裁剪Bitmap
    03.* @param src 源Bitmap
    04.* @param x 开始x坐标
    05.* @param y 开始y坐标
    06.* @param width 截取宽度
    07.* @param height 截取高度
    08.* @return Bitmap
    09.*/
    10.public Bitmap cropBitmap2(Bitmap src, final int x, final int y, final int width,
    11.final int height) {
    12.if (x == 0 && y == 0 && width == src.getWidth() && height == src.getHeight()) {
    13.return src;
    14.}
    15.if (x + width > src.getWidth()) {
    16.throw new IllegalArgumentException("x + width must be <= bitmap.width()");
    17.}
    18.if (y + height > src.getHeight()) {
    19.throw new IllegalArgumentException("y + height must be <= bitmap.height()");
    20.}
    21.return handle(src, new IHandler() {
    22.@Override
    23.public Mat proc(Mat mat_bmp) {
    24.Rect roi = new Rect(x, y, width, height);
    25.Mat mat_new = new Mat(mat_bmp, roi);
    26.return mat_new;
    27.}
    28.});
    29.}

    5. 旋转

     

    01./**
    02.* @brief 旋转Bitmap,逆时针
    03.* @param src 源Bitmap
    04.* @param degree 旋转角度
    05.* @return Bitmap
    07.*/
    08.public Bitmap rotateBitmap2(Bitmap src, final int degree) {
    09.if (degree % 360 == 0) {
    10.return src;
    11.}
    12.return handle(src, new IHandler() {
    13.@Override
    14.public Mat proc(Mat mat_bmp) {
    15.// 计算旋转后图像的宽高
    16.double radians = Math.toRadians(degree);
    17.double sin = Math.abs(Math.sin(radians));
    18.double cos = Math.abs(Math.cos(radians));
    19.int width = mat_bmp.width();
    20.int height = mat_bmp.height();
    21.int newWidth = (int) (width * cos + height * sin);
    22.int newHeight = (int) (width * sin + height * cos);
    23.// 能把原图像和旋转后图像同时放入的外框
    24.int frameWidth = Math.max(width, newWidth);
    25.int frameHeight = Math.max(height, newHeight);
    26.Size frameSize = new Size(frameWidth, frameHeight);
    27.Mat mat_frame = new Mat(frameSize, mat_bmp.type());
    28.// 将原图像copy进外框
    29.int offsetX = (frameWidth - width) / 2;
    30.int offsetY = (frameHeight - height) / 2;
    31.Mat mat_frame_submat = mat_frame.submat(offsetY, offsetY + height, offsetX, offsetX
    32.+ width);
    33.mat_bmp.copyTo(mat_frame_submat);
    34.// 旋转外框
    35.Point center = new Point(frameWidth / 2, frameHeight / 2);
    36.Mat mat_rot = Imgproc.getRotationMatrix2D(center, degree, 1.0);
    37.Mat mat_res = new Mat(); // result
    38.Imgproc.warpAffine(mat_frame, mat_res, mat_rot, frameSize, Imgproc.INTER_LINEAR,
    39.Imgproc.BORDER_CONSTANT, Scalar.all(0));
    40.// 从旋转后的外框获取新图像
    41.offsetX = (frameWidth - newWidth) / 2;
    42.offsetY = (frameHeight - newHeight) / 2;
    43.Mat mat_res_submat = mat_res.submat(offsetY, offsetY + newHeight, offsetX, offsetX
    44.+ newWidth);
    45.return mat_res_submat;
    46.}
    47.});
    48.}

    6. Bitmap效果器

     

    001./**
    002.* @brief Bitmap效果器
    003.* @author join
    004.*/
    005.public static class Effector {
    006.private Config config;
    007.private Mat mat;
    008.private boolean isGray;
    009.private Mat mSepiaKernel;
    010./**
    011.* @brief 构造函数
    012.* @param bmp 源Bitmap
    013.* @param config 'ARGB_8888' or 'RGB_565'
    014.*/
    015.public Effector(Bitmap bmp, Config config) {
    016.Mat mat_bmp = new Mat(bmp.getHeight(), bmp.getWidth(), CvType.CV_8UC4);
    017.Utils.bitmapToMat(bmp, mat_bmp, false); // Bitmap->Mat
    018.this.mat = mat_bmp;
    019.this.config = config;
    020.this.isGray = false;
    021.}
    022./**
    023.* @brief 构造函数,config默认为RGB_565
    024.* @see #BitmapUtil(Bitmap, Config)
    025.*/
    026.public Effector(Bitmap bmp) {
    027.this(bmp, Bitmap.Config.RGB_565);
    028.}
    029./**
    030.* @brief 创建Bitmap
    031.* @return Bitmap
    032.*/
    033.public Bitmap create() {
    034.Mat mat_new = this.mat;
    035.if (isGray) {
    036.Mat mat_gray = new Mat(mat_new.rows(), mat_new.cols(), CvType.CV_8UC4);
    037.Imgproc.cvtColor(mat_new, mat_gray, Imgproc.COLOR_GRAY2BGRA, 4); // 转为灰度4通道Mat
    038.mat_new = mat_gray;
    039.}
    040.Bitmap bmp_new = Bitmap.createBitmap(mat_new.cols(), mat_new.rows(), this.config);
    041.Utils.matToBitmap(mat_new, bmp_new, false); // Mat->Bitmap
    042.return bmp_new;
    043.}
    044./**
    045.* @brief 灰度化Bitmap
    046.*/
    047.public Effector gray() {
    048.Mat mat_bmp = this.mat;
    049.Mat mat_gray = new Mat();
    050.Imgproc.cvtColor(mat_bmp, mat_gray, Imgproc.COLOR_BGRA2GRAY, 1); // 转为灰度单通道Mat
    051.this.mat = mat_gray;
    052.this.isGray = true;
    053.return this;
    054.}
    055./**
    056.* @brief Bitmap二值化
    057.* @pre 需先灰度化{@link #gray()}
    058.* @param thresh 阈值。type为THRESH_OTSU时无用,其自适应区域阈值。
    059.* @param maxval 最大值。type为THRESH_BINARY或THRESH_BINARY_INV时才使用。
    060.* @param type 运算类型
    061.* @see Imgproc#threshold(Mat, Mat, double, double, int)
    062.* @see THRESH_OTSU: {@link Imgproc#adaptiveThreshold(Mat, Mat, double, int, int, int, double)}
    063.*/
    064.public Effector threshold(double thresh, double maxval, int type) {
    065.if (!isGray) {
    066.// throw new IllegalArgumentException("must call gray() before this.");
    067.gray();
    068.}
    069.Mat mat_gray = this.mat;
    070.Imgproc.threshold(mat_gray, mat_gray, thresh, maxval, type);
    071.return this;
    072.}
    073./**
    074.* @brief Bitmap二值化
    075.* @details thresh: 127; maxval: 255; type: THRESH_OTSU;
    076.* @see #threshold(double, double, int)
    077.*/
    078.public Effector threshold() {
    079.return threshold(127, 255, Imgproc.THRESH_OTSU);
    080.}
    081./**
    082.* @brief Canny算子边缘检测
    083.* @param threshold1 控制边缘连接的下限阈值
    084.* @param threshold2 控制强边缘的初始分割的上阈限值
    085.*  如果一个像素的梯度大于上阈限值,则被认为是边缘像素,如果小于下限阈值,则被抛弃。
    086.*  如果该点的梯度在两者之间则当这个点与高于上阈限值的像素点连接时我们才保留,否则抛弃。
    087.*/
    088.public Effector canny(final double threshold1, final double threshold2) {
    089.Mat mat = this.mat;
    090.Imgproc.Canny(mat, mat, threshold1, threshold2, 3, false); // Canny边缘检测
    091.return this;
    092.}
    093./**
    094.* @brief Canny边缘检测,返回为RGB_565
    095.* @details threshold1: 80; threshold2: 90;
    096.* @see #canny(Bitmap, Config)
    097.*/
    098.public Effector canny() {
    099.return canny(80, 90);
    100.}
    101./**
    102.* @brief Sobel处理
    103.*/
    104.public Effector sobel() {
    105.Mat mat = this.mat;
    106.Imgproc.Sobel(mat, mat, CvType.CV_8U, 1, 1); // 一阶差分
    107.Core.convertScaleAbs(mat, mat, 10, 0); // 线性变换
    108.return this;
    109.}
    110./**
    111.* @brief 棕褐色
    112.*/
    113.public Effector sepia() {
    114.Mat mat = this.mat;
    115.Core.transform(mat, mat, getSepiaKernel());
    116.return this;
    117.}
    118.private Mat getSepiaKernel() {
    119.if (mSepiaKernel != null) {
    120.return mSepiaKernel;
    121.}
    122.mSepiaKernel = new Mat(4, 4, CvType.CV_32F);
    123.mSepiaKernel.put(0, 0, /* R */0.189f, 0.769f, 0.393f, 0f);
    124.mSepiaKernel.put(1, 0, /* G */0.168f, 0.686f, 0.349f, 0f);
    125.mSepiaKernel.put(2, 0, /* B */0.131f, 0.534f, 0.272f, 0f);
    126.mSepiaKernel.put(3, 0, /* A */0.000f, 0.000f, 0.000f, 1f);
    127.return mSepiaKernel;
    128.}
    129.}

    # Over


    常用的一些方法就这样了^^。

  • 相关阅读:
    job owner的权限和sql agent start account权限在job调用和job执行的各个阶段起什么作用?
    【转帖】SharePoint 2010中的沙盒解决方案(Sandboxed Solution)
    [ZT]使用IIS作为宿主的WCF服务出现HTTP Error 404.3 Not Found错误的解决办法
    [zt]SharePoint Calculate date column 日期计算列(20100916 23:04:14)
    PortalSiteMapProvider was unable to fetch children for node
    [ZT]SharePoint列表导入/导出命令 SharePoint列表导入/导出命令
    [ZT]一个女IT民工的梦
    “System.Collections.Generic.IEnumerable<TestDAL.HistoryData>”不包含“ToList”的定义
    C#生成随机序列
    利用C#线程窗口调试多线程程序
  • 原文地址:https://www.cnblogs.com/carl2380/p/4192194.html
Copyright © 2020-2023  润新知