亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java如何高效使用OpenCV圖像處理庫(kù)

 更新時(shí)間:2024年03月04日 10:37:35   作者:qq_41983414  
OpenCV是一個(gè)開源的計(jì)算機(jī)視覺庫(kù),它提供了一系列豐富的圖像處理和計(jì)算機(jī)視覺算法,包括圖像讀取、顯示、濾波、特征檢測(cè)、目標(biāo)跟蹤等功能,這篇文章主要給大家介紹了關(guān)于Java如何高效使用OpenCV圖像處理庫(kù)的相關(guān)資料,需要的朋友可以參考下

前言

Java中使用OpenCV圖像處理庫(kù),是通過JNI + 動(dòng)態(tài)鏈接庫(kù)的方式進(jìn)行庫(kù)函數(shù)調(diào)用的。因此會(huì)產(chǎn)生多次native函數(shù)調(diào)用,而JNI調(diào)用會(huì)產(chǎn)生額外的性能開銷,這將導(dǎo)致圖像處理的速度急劇減慢。下面我將演示幾個(gè)常見的示例:

一、遍歷獲取圖像所有像素的RGB值

錯(cuò)誤示例:

 public static void processMat(Mat mat){
    byte[] rgb = new byte[3];
    for(int i = 0;i < mat.rows();i++){
        for(int j = 0;j < mat.cols();j++){
            mat.get(i,j,rgb);
            int r = (rgb[2] & 0xff);
            int g = (rgb[1] & 0xff);
            int b = (rgb[0] & 0xff);
            //處理像素RGB值
                    
        }
    }
}

上面的代碼看似十分符合人類的邏輯思維,意圖簡(jiǎn)潔明了,但實(shí)際運(yùn)行的效率時(shí)十分低的。測(cè)試代碼對(duì)電腦全屏截圖(分辨率1500*1000)后,調(diào)用processMat()函數(shù)的運(yùn)行時(shí)間如下:

遍歷一張全屏截圖居然要2秒鐘! 這還玩?zhèn)€P OpenCV啊。

實(shí)際上,看似簡(jiǎn)單的循環(huán)遍歷代碼背后,隱藏著無數(shù)次native函數(shù)調(diào)用,而這些調(diào)用存在額外性能開銷,例如:查找dll函數(shù)入口地址表,Java到C數(shù)據(jù)類型的內(nèi)存存儲(chǔ)格式轉(zhuǎn)換,參數(shù)傳遞,返回等等。

代碼優(yōu)化

上面的代碼中,光是調(diào)用Mat.rows()和Mat.cols()就有150萬次。經(jīng)過測(cè)試,光執(zhí)行這樣的空循環(huán)(1500 * 1000),就要耗時(shí)35ms

for(int i = 0;i < mat.rows();i++){
    for(int j = 0;j < mat.cols();j++){
    }
}

顯然,rows()和cols()函數(shù)屬于重復(fù)執(zhí)行相同的功能了。那么就把它們挪到循環(huán)外面只執(zhí)行一次。

int rows = mat.rows();
int cols = mat.cols();
for(int i = 0;i < rows;i++){
    for(int j = 0;j < cols;j++){
    }
}

優(yōu)化后,執(zhí)行速度降低到了2ms

還沒完,現(xiàn)在只把代碼的運(yùn)行速度提升了幾十毫秒,真正的耗時(shí)大頭在獲取每一個(gè)像素的RGB值Mat.get()函數(shù)上。

遍歷圖像時(shí),如果我們每次循環(huán)都去調(diào)用dll庫(kù)獲取一個(gè)圖像像素點(diǎn),那么總共150萬個(gè)像素點(diǎn)就要調(diào)用150萬次native函數(shù),每次卻只獲得一個(gè)像素的RGB值,這也太低效了吧。

解決方案已經(jīng)顯而易見了,那就是一次性獲取所有像素的RGB值數(shù)組到Java中,這樣只需要一次數(shù)據(jù)類型轉(zhuǎn)換開銷,效率大大提升。

public static void highSpeed(Mat mat){
    int rows = mat.rows();
    int cols = mat.cols();
    int channels = mat.channels();
    //像素?cái)?shù)組大小: 行數(shù) * 列數(shù) * 顏色通道數(shù)
    byte[] pixels = new byte[rows * cols * channels];
    //通過一次native調(diào)用獲取整個(gè)圖片的像素?cái)?shù)組
    mat.get(0,0,pixels);
    //遍歷像素?cái)?shù)組
    int inner = cols * channels;
    for(int i = 0; i < rows; i++){
        for(int j = 0; j < inner; j += channels){
            int index = i * inner + j;
            int r = (pixels[index + 2] & 0xff);
            int g = (pixels[index + 1] & 0xff);
            int b = (pixels[index] & 0xff);
            //處理RGB值
            
        }
    }
}

使用以下測(cè)試代碼進(jìn)行測(cè)試:

太好了,150萬個(gè)像素RGB值獲取只用了5毫秒!

二、高效BufferedImage和Mat對(duì)象互相轉(zhuǎn)換

BufferedImage時(shí)Java中提供的最常用的帶緩沖圖像處理對(duì)象,不僅可以直接對(duì)圖像的像素?cái)?shù)組進(jìn)行操作,還能使用此類封裝的函數(shù)對(duì)圖像進(jìn)行裁剪,復(fù)制,縮放,顏色類型轉(zhuǎn)換和繪畫等操作。

此外,Robot類提供的屏幕截圖函數(shù)返回的也是BufferedImage對(duì)象。

提升效率的原理和上面一樣,就是將BufferedImage的圖像像素?cái)?shù)組一次性賦值給OpenCV的Mat對(duì)象,千萬不要循環(huán)一個(gè)個(gè)獲取再賦值!

public static Mat toMat(BufferedImage bi) {
   Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3);
   mat.put(0, 0, ((DataBufferByte) bi.getRaster().getDataBuffer()).getData());
   return mat;
}
 
public static BufferedImage toBufferedImage(Mat mat){
    int type = BufferedImage.TYPE_BYTE_GRAY;
    if (mat.channels() > 1) {
    	//注意OpenCV的顏色格式是BGR,所以BufferedImage格式也設(shè)為BGR
        type = BufferedImage.TYPE_3BYTE_BGR;
    }
    BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
    mat.get(0, 0, ((DataBufferByte)image.getRaster().getDataBuffer()).getData());
    return image;
}

這里有個(gè)小細(xì)節(jié),OpenCV中處理的彩色圖像默認(rèn)格式是BGR格式,但我們用Java從屏幕截圖或文件中獲取圖片時(shí)得到的圖片格式都是RGB格式,為了保證轉(zhuǎn)換后顏色的正確性,BufferedImage必須先轉(zhuǎn)為BGR格式。

//原始BufferedImage圖像
BufferedImage image = 。。。;
//轉(zhuǎn)換成RGB格式
BufferedImage rgb = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(image, rgb);

三、高效從屏幕截圖和圖片文件中獲取Mat對(duì)象

//配合上面的 toMat() 使用: OpenCV.toMat(screenShot(0,0,100,100));
public static BufferedImage screenshot(int x,int y,int width,int height){
    BufferedImage image = robot.createScreenCapture(new Rectangle(x,y,width,height));
    //轉(zhuǎn)換成RGB格式
    BufferedImage rgb = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
    new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(image, rgb);
    return rgb;
}
//配合上面的 toMat() 使用: OpenCV.toMat(readImageFile(""));
public static BufferedImage readImageFile(String path){
    try {
        BufferedImage image =  ImageIO.read(new BufferedInputStream(new FileInputStream(path)));
        //轉(zhuǎn)換成RGB格式
        BufferedImage rgb = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
        new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(image, rgb);
        return rgb;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

總結(jié)

過于抽象的編程讓我們的開發(fā)效率提高了,但同時(shí)使得函數(shù)失去了透明性,開發(fā)者根本不知道,也根本不用去關(guān)心底層函數(shù)的實(shí)現(xiàn)原理是什么,能跑就完了。例如Python語(yǔ)言,原生循環(huán)的運(yùn)行效率非常低,因?yàn)槊看窝h(huán)語(yǔ)句都要被虛擬機(jī)動(dòng)態(tài)編譯再運(yùn)行,為了高效處理大批量數(shù)據(jù),py提供了Numpy庫(kù)。在Numpy中進(jìn)行向量化操作時(shí),實(shí)際上是在進(jìn)行一些底層的操作,這些操作是由C語(yǔ)言實(shí)現(xiàn)的,因此它們的執(zhí)行效率非常高。而我們要做的,就是在底層調(diào)用和上層開發(fā)效率之間取得一個(gè)平衡點(diǎn),兼顧代碼的可維護(hù)性和運(yùn)行效率。

到此這篇關(guān)于Java如何高效使用OpenCV圖像處理庫(kù)的文章就介紹到這了,更多相關(guān)Java高效使用OpenCV內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java關(guān)鍵字static學(xué)習(xí)心得

    java關(guān)鍵字static學(xué)習(xí)心得

    本篇文章給大家分享一篇關(guān)于java關(guān)鍵字static的學(xué)習(xí)心得,有這方面需要的朋友學(xué)習(xí)下吧。
    2018-01-01
  • Java之如何截取視頻第一幀

    Java之如何截取視頻第一幀

    這篇文章主要介紹了Java之如何截取視頻第一幀問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • MyEclipse8.6首次運(yùn)行maven項(xiàng)目圖標(biāo)上沒有小M的標(biāo)識(shí)怎么解決

    MyEclipse8.6首次運(yùn)行maven項(xiàng)目圖標(biāo)上沒有小M的標(biāo)識(shí)怎么解決

    myeclipse8.6導(dǎo)入maven項(xiàng)目后識(shí)別為普通java項(xiàng)目,即項(xiàng)目圖標(biāo)上沒有小M的標(biāo)識(shí)。這時(shí)是無法直接運(yùn)行的,怎么解決這一問題呢?下面小編給大家?guī)砹私鉀Q方案,需要的朋友參考下吧
    2016-11-11
  • LeetCode?動(dòng)態(tài)規(guī)劃之矩陣區(qū)域和詳情

    LeetCode?動(dòng)態(tài)規(guī)劃之矩陣區(qū)域和詳情

    這篇文章主要介紹了LeetCode?動(dòng)態(tài)規(guī)劃之矩陣區(qū)域和詳情,文章基于Java的相關(guān)資料展開對(duì)LeetCode?動(dòng)態(tài)規(guī)劃的詳細(xì)介紹,需要的小伙伴可以參考一下
    2022-04-04
  • SpringBoot整合Redis使用@Cacheable和RedisTemplate

    SpringBoot整合Redis使用@Cacheable和RedisTemplate

    本文主要介紹了SpringBoot整合Redis使用@Cacheable和RedisTemplate,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • 數(shù)據(jù)定位在java購(gòu)物車系統(tǒng)中的應(yīng)用

    數(shù)據(jù)定位在java購(gòu)物車系統(tǒng)中的應(yīng)用

    實(shí)現(xiàn)"加入購(gòu)物車"功能,數(shù)據(jù)定位至關(guān)重要,它通過用戶ID和商品ID等標(biāo)識(shí)符實(shí)現(xiàn)快速查詢和數(shù)據(jù)一致性,主鍵、外鍵和聯(lián)合索引等數(shù)據(jù)庫(kù)技術(shù),以及Redis緩存和并發(fā)控制策略如樂觀鎖或分布式鎖,共同保障了購(gòu)物車系統(tǒng)的查詢效率和數(shù)據(jù)安全,這些機(jī)制對(duì)高并發(fā)和大數(shù)據(jù)量的場(chǎng)景尤為重要
    2024-10-10
  • 深入解讀 Spring Boot 生態(tài)之功能、組件與優(yōu)勢(shì)

    深入解讀 Spring Boot 生態(tài)之功能、組件與優(yōu)勢(shì)

    本文將深入剖析 Spring Boot 的生態(tài)體系,包括其核心功能、生態(tài)組件以及在不同場(chǎng)景中的應(yīng)用,并附上一張 Spring Boot 生態(tài)系統(tǒng)圖,幫助開發(fā)者更直觀地理解 Spring Boot 的強(qiáng)大之處,感興趣的朋友一起看看吧
    2024-11-11
  • IDEA工程運(yùn)行時(shí)總是報(bào)xx程序包不存在實(shí)際上包已導(dǎo)入(問題分析及解決方案)

    IDEA工程運(yùn)行時(shí)總是報(bào)xx程序包不存在實(shí)際上包已導(dǎo)入(問題分析及解決方案)

    這篇文章主要介紹了IDEA工程運(yùn)行時(shí),總是報(bào)xx程序包不存在,實(shí)際上包已導(dǎo)入,本文給大家分享問題分析及解決方案,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2020-08-08
  • java多線程讀取多個(gè)文件的方法

    java多線程讀取多個(gè)文件的方法

    這篇文章主要為大家詳細(xì)介紹了java多線程讀取多個(gè)文件的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • JedisPool資源池優(yōu)化方法

    JedisPool資源池優(yōu)化方法

    這篇文章主要介紹了JedisPool資源池優(yōu)化方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03

最新評(píng)論