python怎么使用OpenCV獲取高動態(tài)范圍成像HDR
Jun 02, 2023 pm 07:54 PM1 背景
1.1 什么是高動態(tài)范圍(HDR)成像?
大多數(shù)數(shù)碼相機和顯示器將彩色圖像捕獲或顯示為24位矩陣。由于每個顏色通道具有8位,而共有三個通道,因此每個通道的像素值范圍是0至255。換句話說,普通相機或顯示器具有有限的動態(tài)范圍。
然而,我們周圍的世界顏色有一個非常大的變化范圍。當(dāng)燈關(guān)閉時,車庫會變黑;太陽照射下,車庫看起來變得非常明亮。即使忽略極端情況,八位在常規(guī)情況下也幾乎無法完全捕捉場景。因此,相機會嘗試估計光線并自動設(shè)置曝光,以使圖像中最有用的部分具有良好的動態(tài)顏色范圍,而太暗和太亮的部分分別被設(shè)置為0和255。
在下圖中,左側(cè)的圖像是正常曝光的圖像。請注意,背景中的天空已完全消失,因為相機決定使用一個能夠讓小孩被正確拍攝而明亮的天空被忽略的設(shè)置。右側(cè)圖像是iPhone生成的HDR圖像。
iPhone通過在三種不同的曝光下拍攝三張圖片來捕獲HDR圖像。圖像是連續(xù)快速拍攝的,因此三次拍攝之間幾乎沒有偏移。然后組合三個圖像以產(chǎn)生HDR圖像。
1.2 高動態(tài)范圍(HDR)成像如何工作?
在本節(jié)中,我們將介紹使用OpenCV創(chuàng)建HDR圖像的步驟。
1)使用不同曝光設(shè)置拍攝多張圖像
當(dāng)我們在使用相機拍攝時,每個通道只有8位用于表示場景的動態(tài)范圍(亮度范圍)。但是我們可以通過改變快門速度在不同曝光下拍攝場景的多個圖像。大多數(shù)單反相機都有一個稱為自動包圍曝光(AEB)的功能,只需按一下按鈕,我們就可以在不同曝光下拍攝多張照片。在相機上使用AEB或在手機上使用自動包圍應(yīng)用程序,我們可以一個接一個地快速拍攝多張照片,因此場景不會改變。若要在iPhone上使用HDR模式,則需要拍攝三張照片(對于安卓手機則可下載超級相機應(yīng)用程序?qū)崿F(xiàn)此功能)。
1曝光不足的圖像:此圖片比正確的曝光圖像暗。目標(biāo)是拍攝非常明亮的圖像部分。
2正確曝光的圖像:這是相機根據(jù)估計的照明度拍攝的常規(guī)圖像。
3過度曝光的圖像:此圖片比正確的曝光圖像亮。目標(biāo)是捕捉非常黑暗的圖像部分。
當(dāng)場景的動態(tài)范圍非常大時,我們可以采用拍攝三張或更多照片的方法來生成HDR圖像。在本教程中,我們將使用曝光時間為1/30,0.25,2.5和15秒拍攝的4張圖像??s略圖如下所示。
通常,與SLR相機或手機相關(guān)的曝光時間和其他設(shè)置的信息會被儲存在JPEG文件的EXIF元數(shù)據(jù)中。您可以通過以下鏈接學(xué)習(xí)如何查看存儲在Windows和Mac中的JPEG文件中的EXIF元數(shù)據(jù)。
windows下右鍵圖片-屬性-詳細(xì)信息,有圖像具體信息。如下所示:
或者,您可以使用我最喜歡的名為EXIFTOOL的EXIF命令行實用程序。
2 代碼
2.1 運行環(huán)境配置
由于本文所用代碼涉及到opencv非免費代碼,createTonemapMantiuk
這部分算法都是申請專利需要收費(本文可以不要這段代碼)。在使用時編譯opencv和opencv_contrib需要選擇OPENCV_ENABLE_NONFREE
。
如果是python,直接安裝指定版本opencv就行了:
pip install opencv-contrib-python==3.4.2.17
在使用非免費代碼
頭文件和命名空間如下:
#include <opencv2/xphoto.hpp> using namespace xphoto;
2.2 讀取圖像和曝光時間
手動輸入圖像,曝光時間以及圖像個數(shù)。
代碼如下: C++:
/** * @brief 讀圖 * * @param images * @param times */ void readImagesAndTimes(vector<Mat> &images, vector<float> ×) { //圖像個數(shù) int numImages = 3; //圖像曝光時間 static const float timesArray[] = { 1.0 / 25 ,1.0 / 17, 1.0 / 13 }; times.assign(timesArray, timesArray + numImages); static const char* filenames[] = { "1_25.jpg", "1_17.jpg", "1_13.jpg"}; //讀取圖像 for (int i = 0; i < numImages; i++) { Mat im = imread(filenames[i]); images.push_back(im); } }
python:
def readImagesAndTimes(): # List of exposure times times = np.array([ 1/30.0, 0.25, 2.5, 15.0 ], dtype=np.float32) # List of image filenames filenames = ["img_0.033.jpg", "img_0.25.jpg", "img_2.5.jpg", "img_15.jpg"] images = [] for filename in filenames: im = cv2.imread(filename) images.append(im) return images, times
2.3 圖像對齊
用于合成HDR圖像的原始圖像未對準(zhǔn)可能導(dǎo)致嚴(yán)重的偽影。在下圖中,左側(cè)圖像是使用未對齊圖像組成的HDR圖像,右側(cè)圖像是使用對齊圖像的圖像。我們在左側(cè)圖像中發(fā)現(xiàn)了明顯的重疊缺陷,這是通過放大圖像的一部分并使用紅色圓圈進行標(biāo)識得出的。
當(dāng)然,在拍攝用于創(chuàng)建HDR圖像的照片時,專業(yè)攝影師將相機安裝在三腳架上。他們還使用一種稱為反光鏡鎖死的功能來減少額外的振動。即使這樣,圖像也可能無法完美對齊,因為無法保證無振動的環(huán)境。使用手持相機或手機拍攝圖像時,對齊問題會變得更糟。
OpenCV 提供了一個簡單的AlignMTB方法,可以幸運地對齊這些圖像。所有圖像都會被轉(zhuǎn)換為中值閾值位圖(MTB)格式,這是由該算法完成的。圖像的MTB生成方式為將比中值亮度亮的點分配為1,其余為0。MTB不隨曝光時間的改變而改變。因此不需要我們指定曝光時間就可以對齊MTB。
代碼如下:
C++:
// Align input images Ptr<AlignMTB> alignMTB = createAlignMTB(); alignMTB->process(images, images);
python:
# Align input images alignMTB = cv2.createAlignMTB() alignMTB.process(images, images)
2.4 恢復(fù)相機響應(yīng)功能
典型相機的響應(yīng)與場景亮度不是線性的。如果一個攝像機拍攝到兩個物體,其中一個物體的亮度是另一個物體在現(xiàn)實世界中的兩倍,那么這句話的意思是什么?。當(dāng)您測量照片中兩個對象的像素強度時,較亮對象的像素值將不會是較暗對象的兩倍。如果不考慮相機的響應(yīng)函數(shù)(CRF),就無法將多張圖像合并為一個HDR圖像。將多個曝光圖像合并為HDR圖像意味著什么?
在圖像的某個位置(x,y)僅考慮一個像素。如果CRF是線性的,則像素值將與曝光時間成正比,除非像素在特定圖像中太暗(即接近0)或太亮(即接近255)。我們可以過濾出這些不好的像素(太暗或太亮),并且將像素值除以曝光時間來估計像素的亮度,然后在像素不差的所有圖像(太暗或太亮)上對亮度值取平均。我們可以對所有像素進行這樣的處理,并通過對“好”像素進行平均來獲得所有像素的單張圖像。但是CRF不是線性的,我們需要在評估CRF前把圖像強度變成線性。
好消息是,如果我們知道每張圖像的曝光時間,可以從圖像中估算CRF。與計算機視覺中的許多問題一樣,找到CRF的問題被設(shè)置為優(yōu)化問題,其中目標(biāo)是最小化由數(shù)據(jù)項和平滑項組成的目標(biāo)函數(shù)。這些問題通常會減少到使用奇異值分解(SVD)求解的線性最小二乘問題,而奇異值分解是所有線性代數(shù)包的一部分。CRF恢復(fù)算法細(xì)節(jié)見論文Recovering High Dynamic Range Radiance Maps from Photographs。
使用CalibrateDebevec
或在OpenCV
中僅使用兩行代碼來查找CRF CalibrateRobertson。在本教程中我們將使用CalibrateDebevec。
代碼如下:
C++:
// Obtain Camera Response Function (CRF) Mat responseDebevec; Ptr<CalibrateDebevec> calibrateDebevec = createCalibrateDebevec(); calibrateDebevec->process(images, responseDebevec, times);
python:
# Obtain Camera Response Function (CRF) calibrateDebevec = cv2.createCalibrateDebevec() responseDebevec = calibrateDebevec.process(images, times)
下圖顯示了使用紅色,綠色和藍(lán)色通道圖像恢復(fù)的CRF。
2.5 合并圖像
當(dāng)我們完成對CRF的估計時,便可以將曝光圖像合并為一個HDR圖像,即MergeDebevec算法。C ++和Python代碼如下所示。
C++:
// Merge images into an HDR linear image Mat hdrDebevec; Ptr<MergeDebevec> mergeDebevec = createMergeDebevec(); mergeDebevec->process(images, hdrDebevec, times, responseDebevec); // Save HDR image. imwrite("hdrDebevec.hdr", hdrDebevec);
Python:
# Merge images into an HDR linear image mergeDebevec = cv2.createMergeDebevec() hdrDebevec = mergeDebevec.process(images, times, responseDebevec) # Save HDR image. cv2.imwrite("hdrDebevec.hdr", hdrDebevec)
上面保存的HDR圖像可以在Photoshop中加載并進行色調(diào)映射。一個例子如下所示。
2.6 色調(diào)映射
現(xiàn)在我們將曝光圖像合并為一個HDR圖像。你能猜出這張圖片的最小和最大像素值嗎?對于漆黑條件,最小值顯然為0。什么是理論最大值?無窮!實際上,不同情況下的最大值是不同的。如果場景包含非常明亮的光源,我們將看到非常大的最大值。我們已經(jīng)利用多個圖像恢復(fù)了相對亮度信息,但我們現(xiàn)在的難點在于將其編碼為24位圖像以便于顯示。
色調(diào)映射:將高動態(tài)范圍(HDR)圖像轉(zhuǎn)換為每通道8位圖像同時保留盡可能多的細(xì)節(jié)的過程稱為色調(diào)映射。
有幾種色調(diào)映射算法。OpenCV實現(xiàn)了其中的四個。要記住的是,沒有正確的方法來進行色調(diào)映射。通常,我們希望在色調(diào)映射圖像中看到比在任何一個曝光圖像中更多的細(xì)節(jié)。有時,色調(diào)映射的目標(biāo)是產(chǎn)生逼真的圖像,并且通常目標(biāo)是產(chǎn)生超現(xiàn)實的圖像。OpenCV實現(xiàn)的算法偏向于生成逼真的結(jié)果,因此可能不太引人注目。
我們來看看各種選項。下面列出了不同色調(diào)映射算法的一些常見參數(shù)。
1)伽馬gamma:此參數(shù)通過應(yīng)用伽馬校正來壓縮動態(tài)范圍。當(dāng)gamma等于1時,不應(yīng)用校正。小于1的灰度會使圖像變暗,而大于1的灰度會使圖像變亮。
2)飽和度saturation:此參數(shù)用于增加或減少飽和度。當(dāng)飽和度高時,顏色更豐富,更強烈。飽和度值接近零,使顏色漸漸變?yōu)榛叶取?/p>
3)對比度contrast:控制輸出圖像的對比度(即log(maxPixelValue / minPixelValue))。
讓我們來探索OpenCV中可用的四種色調(diào)映射算法
Drago Tonemap
Drago Tonemap的參數(shù)如下所示:
createTonemapDrago ( float gamma = 1.0f, float saturation = 1.0f, float bias = 0.85f )
這里,bias是[0,1]范圍內(nèi)偏置函數(shù)的值。從0.7到0.9的值通常會得到最好的結(jié)果。默認(rèn)值為0.85。有關(guān)更多技術(shù)細(xì)節(jié),請參閱此文章。參數(shù)通過反復(fù)試驗獲得。最終輸出乘以3只是因為它給出了最令人滿意的結(jié)果。更多的技術(shù)細(xì)節(jié)見:
結(jié)果如下所示:
Durand Tonemap
Durand Tonemap的參數(shù)如下所示:
createTonemapDurand ( float gamma = 1.0f, float contrast = 4.0f, float saturation = 1.0f, float sigma_space = 2.0f, float sigma_color = 2.0f );
該算法基于將圖像分解為基礎(chǔ)層和細(xì)節(jié)層。使用稱為雙邊濾波器的邊緣保留濾波器獲得基礎(chǔ)層。雙邊濾波器中的參數(shù)sigma_space和sigma_color分別影響空間域和顏色域的平滑程度。更多的技術(shù)細(xì)節(jié)見:
結(jié)果如下所示:
Reinhard Tonemap
Reinhard Tonemap的參數(shù)如下所示:
createTonemapReinhard ( float gamma = 1.0f, float intensity = 0.0f, float light_adapt = 1.0f, float color_adapt = 0.0f )
參數(shù)intensity應(yīng)在[-8,8]范圍內(nèi)。強度值越大,結(jié)果越明亮。參數(shù)light_adapt控制燈光適應(yīng)并且在[0,1]范圍內(nèi)。值1表示僅基于像素值的自適應(yīng),值0表示全局自適應(yīng)。中間值可以用于兩者的加權(quán)組合。參數(shù)color_adapt控制色度適應(yīng)并且在[0,1]范圍內(nèi)。當(dāng)值為1時,通道單獨處理;當(dāng)值為0時,所有通道適應(yīng)級別相同。中間值可用于兩者的加權(quán)組合。更多的技術(shù)細(xì)節(jié)見:
結(jié)果如下所示:
Mantiuk Tonemap
Mantiuk Tonemap的參數(shù)如下所示:
createTonemapMantiuk ( float gamma = 1.0f, float scale = 0.7f, float saturation = 1.0f )
scale是對比度比例因子。從0.6到0.9的值產(chǎn)生最佳結(jié)果。更多的技術(shù)細(xì)節(jié)見:
結(jié)果如下所示:
上面所有色調(diào)映射代碼見:
C++:
// Tonemap using Drago's method to obtain 24-bit color image 色調(diào)映射算法 cout << "Tonemaping using Drago's method ... "; Mat ldrDrago; Ptr<TonemapDrago> tonemapDrago = createTonemapDrago(1.0, 0.7); tonemapDrago->process(hdrDebevec, ldrDrago); ldrDrago = 3 * ldrDrago; imwrite("ldr-Drago.jpg", ldrDrago * 255); cout << "saved ldr-Drago.jpg" << endl; // Tonemap using Durand's method obtain 24-bit color image 色調(diào)映射算法 cout << "Tonemaping using Durand's method ... "; Mat ldrDurand; Ptr<TonemapDurand> tonemapDurand = createTonemapDurand(1.5, 4, 1.0, 1, 1); tonemapDurand->process(hdrDebevec, ldrDurand); ldrDurand = 3 * ldrDurand; imwrite("ldr-Durand.jpg", ldrDurand * 255); cout << "saved ldr-Durand.jpg" << endl; // Tonemap using Reinhard's method to obtain 24-bit color image 色調(diào)映射算法 cout << "Tonemaping using Reinhard's method ... "; Mat ldrReinhard; Ptr<TonemapReinhard> tonemapReinhard = createTonemapReinhard(1.5, 0, 0, 0); tonemapReinhard->process(hdrDebevec, ldrReinhard); imwrite("ldr-Reinhard.jpg", ldrReinhard * 255); cout << "saved ldr-Reinhard.jpg" << endl; // Tonemap using Mantiuk's method to obtain 24-bit color image 色調(diào)映射算法 cout << "Tonemaping using Mantiuk's method ... "; Mat ldrMantiuk; Ptr<TonemapMantiuk> tonemapMantiuk = createTonemapMantiuk(2.2, 0.85, 1.2); tonemapMantiuk->process(hdrDebevec, ldrMantiuk); ldrMantiuk = 3 * ldrMantiuk; imwrite("ldr-Mantiuk.jpg", ldrMantiuk * 255); cout << "saved ldr-Mantiuk.jpg" << endl;
Python:
# Tonemap using Drago's method to obtain 24-bit color image print("Tonemaping using Drago's method ... ") tonemapDrago = cv2.createTonemapDrago(1.0, 0.7) ldrDrago = tonemapDrago.process(hdrDebevec) ldrDrago = 3 * ldrDrago cv2.imwrite("ldr-Drago.jpg", ldrDrago * 255) print("saved ldr-Drago.jpg") # Tonemap using Durand's method obtain 24-bit color image print("Tonemaping using Durand's method ... ") tonemapDurand = cv2.createTonemapDurand(1.5,4,1.0,1,1) ldrDurand = tonemapDurand.process(hdrDebevec) ldrDurand = 3 * ldrDurand cv2.imwrite("ldr-Durand.jpg", ldrDurand * 255) print("saved ldr-Durand.jpg") # Tonemap using Reinhard's method to obtain 24-bit color image print("Tonemaping using Reinhard's method ... ") tonemapReinhard = cv2.createTonemapReinhard(1.5, 0,0,0) ldrReinhard = tonemapReinhard.process(hdrDebevec) cv2.imwrite("ldr-Reinhard.jpg", ldrReinhard * 255) print("saved ldr-Reinhard.jpg") # Tonemap using Mantiuk's method to obtain 24-bit color image print("Tonemaping using Mantiuk's method ... ") tonemapMantiuk = cv2.createTonemapMantiuk(2.2,0.85, 1.2) ldrMantiuk = tonemapMantiuk.process(hdrDebevec) ldrMantiuk = 3 * ldrMantiuk cv2.imwrite("ldr-Mantiuk.jpg", ldrMantiuk * 255) print("saved ldr-Mantiuk.jpg")
2.7 工程代碼
本文所有代碼見:
C++:
#include "pch.h" #include <opencv2/opencv.hpp> #include <opencv2/xphoto.hpp> #include <vector> #include <iostream> #include <fstream> using namespace cv; using namespace std; using namespace xphoto; /** * @brief 讀圖 * * @param images * @param times */ void readImagesAndTimes(vector<Mat> &images, vector<float> ×) { //圖像個數(shù) int numImages = 3; //圖像曝光時間 static const float timesArray[] = { 1.0 / 25 ,1.0 / 17, 1.0 / 13 }; times.assign(timesArray, timesArray + numImages); static const char* filenames[] = { "1_25.jpg", "1_17.jpg", "1_13.jpg"}; //讀取圖像 for (int i = 0; i < numImages; i++) { Mat im = imread(filenames[i]); images.push_back(im); } } int main() { // Read images and exposure times 讀取圖像和圖像曝光時間 cout << "Reading images ... " << endl; //圖像 vector<Mat> images; //曝光時間 vector<float> times; //讀取圖像和圖像曝光時間 readImagesAndTimes(images, times); // Align input images 圖像對齊 cout << "Aligning images ... " << endl; Ptr<AlignMTB> alignMTB = createAlignMTB(); alignMTB->process(images, images); // Obtain Camera Response Function (CRF) 獲得CRF cout << "Calculating Camera Response Function (CRF) ... " << endl; Mat responseDebevec; Ptr<CalibrateDebevec> calibrateDebevec = createCalibrateDebevec(); calibrateDebevec->process(images, responseDebevec, times); // Merge images into an HDR linear image 圖像合并為HDR圖像 cout << "Merging images into one HDR image ... "; Mat hdrDebevec; Ptr<MergeDebevec> mergeDebevec = createMergeDebevec(); mergeDebevec->process(images, hdrDebevec, times, responseDebevec); // Save HDR image. 保存HDR圖像 imwrite("hdrDebevec.hdr", hdrDebevec); cout << "saved hdrDebevec.hdr " << endl; // Tonemap using Drago's method to obtain 24-bit color image 色調(diào)映射算法 cout << "Tonemaping using Drago's method ... "; Mat ldrDrago; Ptr<TonemapDrago> tonemapDrago = createTonemapDrago(1.0, 0.7); tonemapDrago->process(hdrDebevec, ldrDrago); ldrDrago = 3 * ldrDrago; imwrite("ldr-Drago.jpg", ldrDrago * 255); cout << "saved ldr-Drago.jpg" << endl; // Tonemap using Durand's method obtain 24-bit color image 色調(diào)映射算法 cout << "Tonemaping using Durand's method ... "; Mat ldrDurand; Ptr<TonemapDurand> tonemapDurand = createTonemapDurand(1.5, 4, 1.0, 1, 1); tonemapDurand->process(hdrDebevec, ldrDurand); ldrDurand = 3 * ldrDurand; imwrite("ldr-Durand.jpg", ldrDurand * 255); cout << "saved ldr-Durand.jpg" << endl; // Tonemap using Reinhard's method to obtain 24-bit color image 色調(diào)映射算法 cout << "Tonemaping using Reinhard's method ... "; Mat ldrReinhard; Ptr<TonemapReinhard> tonemapReinhard = createTonemapReinhard(1.5, 0, 0, 0); tonemapReinhard->process(hdrDebevec, ldrReinhard); imwrite("ldr-Reinhard.jpg", ldrReinhard * 255); cout << "saved ldr-Reinhard.jpg" << endl; // Tonemap using Mantiuk's method to obtain 24-bit color image 色調(diào)映射算法 cout << "Tonemaping using Mantiuk's method ... "; Mat ldrMantiuk; Ptr<TonemapMantiuk> tonemapMantiuk = createTonemapMantiuk(2.2, 0.85, 1.2); tonemapMantiuk->process(hdrDebevec, ldrMantiuk); ldrMantiuk = 3 * ldrMantiuk; imwrite("ldr-Mantiuk.jpg", ldrMantiuk * 255); cout << "saved ldr-Mantiuk.jpg" << endl; return 0; }
Python:
import cv2 import numpy as np def readImagesAndTimes(): times = np.array([ 1/30.0, 0.25, 2.5, 15.0 ], dtype=np.float32) filenames = ["img_0.033.jpg", "img_0.25.jpg", "img_2.5.jpg", "img_15.jpg"] images = [] for filename in filenames: im = cv2.imread(filename) images.append(im) return images, times if __name__ == '__main__': # Read images and exposure times print("Reading images ... ") images, times = readImagesAndTimes() # Align input images print("Aligning images ... ") alignMTB = cv2.createAlignMTB() alignMTB.process(images, images) # Obtain Camera Response Function (CRF) print("Calculating Camera Response Function (CRF) ... ") calibrateDebevec = cv2.createCalibrateDebevec() responseDebevec = calibrateDebevec.process(images, times) # Merge images into an HDR linear image print("Merging images into one HDR image ... ") mergeDebevec = cv2.createMergeDebevec() hdrDebevec = mergeDebevec.process(images, times, responseDebevec) # Save HDR image. cv2.imwrite("hdrDebevec.hdr", hdrDebevec) print("saved hdrDebevec.hdr ") # Tonemap using Drago's method to obtain 24-bit color image print("Tonemaping using Drago's method ... ") tonemapDrago = cv2.createTonemapDrago(1.0, 0.7) ldrDrago = tonemapDrago.process(hdrDebevec) ldrDrago = 3 * ldrDrago cv2.imwrite("ldr-Drago.jpg", ldrDrago * 255) print("saved ldr-Drago.jpg") # Tonemap using Durand's method obtain 24-bit color image print("Tonemaping using Durand's method ... ") tonemapDurand = cv2.createTonemapDurand(1.5,4,1.0,1,1) ldrDurand = tonemapDurand.process(hdrDebevec) ldrDurand = 3 * ldrDurand cv2.imwrite("ldr-Durand.jpg", ldrDurand * 255) print("saved ldr-Durand.jpg") # Tonemap using Reinhard's method to obtain 24-bit color image print("Tonemaping using Reinhard's method ... ") tonemapReinhard = cv2.createTonemapReinhard(1.5, 0,0,0) ldrReinhard = tonemapReinhard.process(hdrDebevec) cv2.imwrite("ldr-Reinhard.jpg", ldrReinhard * 255) print("saved ldr-Reinhard.jpg") # Tonemap using Mantiuk's method to obtain 24-bit color image print("Tonemaping using Mantiuk's method ... ") tonemapMantiuk = cv2.createTonemapMantiuk(2.2,0.85, 1.2) ldrMantiuk = tonemapMantiuk.process(hdrDebevec) ldrMantiuk = 3 * ldrMantiuk cv2.imwrite("ldr-Mantiuk.jpg", ldrMantiuk * 255) print("saved ldr-Mantiuk.jpg")
以上是python怎么使用OpenCV獲取高動態(tài)范圍成像HDR的詳細(xì)內(nèi)容。更多信息請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費脫衣服圖片

Undresser.AI Undress
人工智能驅(qū)動的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover
用于從照片中去除衣服的在線人工智能工具。

Clothoff.io
AI脫衣機

Video Face Swap
使用我們完全免費的人工智能換臉工具輕松在任何視頻中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的代碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
功能強大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級代碼編輯軟件(SublimeText3)

用戶語音輸入通過前端JavaScript的MediaRecorderAPI捕獲并發(fā)送至PHP后端;2.PHP將音頻保存為臨時文件后調(diào)用STTAPI(如Google或百度語音識別)轉(zhuǎn)換為文本;3.PHP將文本發(fā)送至AI服務(wù)(如OpenAIGPT)獲取智能回復(fù);4.PHP再調(diào)用TTSAPI(如百度或Google語音合成)將回復(fù)轉(zhuǎn)為語音文件;5.PHP將語音文件流式返回前端播放,完成交互。整個流程由PHP主導(dǎo)數(shù)據(jù)流轉(zhuǎn)與錯誤處理,確保各環(huán)節(jié)無縫銜接。

要實現(xiàn)PHP結(jié)合AI進行文本糾錯與語法優(yōu)化,需按以下步驟操作:1.選擇適合的AI模型或API,如百度、騰訊API或開源NLP庫;2.通過PHP的curl或Guzzle調(diào)用API并處理返回結(jié)果;3.在應(yīng)用中展示糾錯信息并允許用戶選擇是否采納;4.使用php-l和PHP_CodeSniffer進行語法檢測與代碼優(yōu)化;5.持續(xù)收集反饋并更新模型或規(guī)則以提升效果。選擇AIAPI時應(yīng)重點評估準(zhǔn)確率、響應(yīng)速度、價格及對PHP的支持。代碼優(yōu)化應(yīng)遵循PSR規(guī)范、合理使用緩存、避免循環(huán)查詢、定期審查代碼,并借助X

使用Seaborn的jointplot可快速可視化兩個變量間的關(guān)系及各自分布;2.基礎(chǔ)散點圖通過sns.jointplot(data=tips,x="total_bill",y="tip",kind="scatter")實現(xiàn),中心為散點圖,上下和右側(cè)顯示直方圖;3.添加回歸線和密度信息可用kind="reg",并結(jié)合marginal_kws設(shè)置邊緣圖樣式;4.數(shù)據(jù)量大時推薦kind="hex",用

PHP結(jié)合AI做視頻內(nèi)容分析的核心思路是讓PHP作為后端“膠水”,先上傳視頻到云存儲,再調(diào)用AI服務(wù)(如GoogleCloudVideoAI等)進行異步分析;2.PHP解析返回的JSON結(jié)果,提取人物、物體、場景、語音等信息生成智能標(biāo)簽并存入數(shù)據(jù)庫;3.優(yōu)勢在于利用PHP成熟的Web生態(tài)快速集成AI能力,適合已有PHP系統(tǒng)的項目高效落地;4.常見挑戰(zhàn)包括大文件處理(用預(yù)簽名URL直傳云存儲)、異步任務(wù)(引入消息隊列)、成本控制(按需分析 預(yù)算監(jiān)控)和結(jié)果優(yōu)化(標(biāo)簽規(guī)范化);5.智能標(biāo)簽顯著提升視

要將AI情感計算技術(shù)融入PHP應(yīng)用,核心是利用云服務(wù)AIAPI(如Google、AWS、Azure)進行情感分析,通過HTTP請求發(fā)送文本并解析返回的JSON結(jié)果,將情感數(shù)據(jù)存入數(shù)據(jù)庫,從而實現(xiàn)用戶反饋的自動化處理與數(shù)據(jù)洞察。具體步驟包括:1.選擇適合的AI情感分析API,綜合考慮準(zhǔn)確性、成本、語言支持和集成復(fù)雜度;2.使用Guzzle或curl發(fā)送請求,存儲情感分?jǐn)?shù)、標(biāo)簽及強度等信息;3.構(gòu)建可視化儀表盤,支持優(yōu)先級排序、趨勢分析、產(chǎn)品迭代方向和用戶細(xì)分;4.應(yīng)對技術(shù)挑戰(zhàn),如API調(diào)用限制、數(shù)

字符串列表可用join()方法合并,如''.join(words)得到"HelloworldfromPython";2.數(shù)字列表需先用map(str,numbers)或[str(x)forxinnumbers]轉(zhuǎn)為字符串后才能join;3.任意類型列表可直接用str()轉(zhuǎn)換為帶括號和引號的字符串,適用于調(diào)試;4.自定義格式可用生成器表達式結(jié)合join()實現(xiàn),如'|'.join(f"[{item}]"foriteminitems)輸出"[a]|[

pythoncanbeoptimizedFormized-formemory-boundoperationsbyreducingOverHeadThroughGenerator,有效dattratsures,andManagingObjectLifetimes.first,useGeneratorSInsteadoFlistSteadoflistSteadoFocessLargedAtasetSoneItematatime,desceedingingLoadeGingloadInterveringerverneDraineNterveingerverneDraineNterveInterveIntMory.second.second.second.second,Choos,Choos

pandas.melt()用于將寬格式數(shù)據(jù)轉(zhuǎn)為長格式,答案是通過指定id_vars保留標(biāo)識列、value_vars選擇需融化的列、var_name和value_name定義新列名,1.id_vars='Name'表示Name列不變,2.value_vars=['Math','English','Science']指定要融化的列,3.var_name='Subject'設(shè)置原列名的新列名,4.value_name='Score'設(shè)置原值的新列名,最終生成包含Name、Subject和Score三列
