詳解opencv resize之INTER_LINEAR和INTER_AREA

一。先簡單介紹一下resize的用法

src:輸入圖,

dst:輸出圖

dsize:輸出圖的寬高,如果dsize不為空(即寬高都不是0),則以dsize為準進行resize。

fx, fy是放大縮小的比例,是輸出圖寬(高)與輸入圖的寬(高)的比值,這兩個都有默認值0,如果想直接指定fx, fy,則可以把dsize置空。

interpolation就是插值的方法了,插值的方法有很多種,本貼只分析INTER_AREA與INTER_LINEAR。

例1:通過dsize指定目標圖大小

void resize_demo()
{cv::Mat src = cv::imread("../data/car.jpg");int height   = src.rows;int width    = src.cols;cv::Mat dest;cv::resize(src, dest, cv::Size(width / 2, height / 4), 0, 0, cv::INTER_LINEAR);cv::imwrite("../data/cat_resize.jpg", dest);
}

左邊為原圖,右邊為目標圖?

例2:通過fx, fy指定縮放大小,這次都指定為0.5

void resize_demo1()
{cv::Mat src = cv::imread("../data/car.jpg");int height   = src.rows;int width    = src.cols;cv::Mat dest;cv::resize(src, dest, cv::Size(), 0.5, 0.5, cv::INTER_LINEAR);cv::imwrite("../data/cat_resize.jpg", dest);
}

那么目標圖上的像素值是怎么算出來的呢?

比如一個5乘5的原圖,放大到7乘7目標圖上,目標圖上的(2,2)位置的像素,映射回原圖,x,y坐標都是2*5/7,約為(1.4, 1.4)。如果說正好是(1,1),那就取原圖上(1,1)處的像素值,但現在不是個整數,到底應該怎么取呢?這就涉及到不同的插值算法了。如果我直接取個最近位置的像素值,那就是最近鄰算法了(INTER_NEAREST),比如離(1.4, 1.4)最近的就是(1,1)。

圖1

二。INTER_LINEAR

1.插值邏輯

接上面的問題,如果取(1.4, 1.4)周圍的4個像素的值,并且按照遠近的反比來做一個加權平均,就是雙線性插了。

4個像素值分別為v11, v12, v21, v22(名字就跟坐標對應了),中間那個黑點就是v1.4,4個區域的面積分別為a00, a01, a10, a11,它們的和肯定是1。則v1.4=v11*a11+v12*a10+v21*a01+v22*a00。每個像素乘的都是它斜對面的那個面積,其實直觀理解也說的通,黑點離a11最近,那a11是不是應該分配一個最大的權重。

圖2

具體來分析的話,首先考慮一維場景,在x為1和2的兩個點(v1和v2)中間有一個x=1.4的點,如果用v1和v2來計算v1.4,那按照遠近關系的反比來求加權平均,就直接明顯了,肯定是v1.4=v1*a1+v2*a0

圖3

通過x軸方向上的線性插值,就能求出下圖兩個紫色點的像素值

圖4

然后再用它倆在y軸方向上進行線性插值,就能求出最終的v1.4了,所以叫雙線性插值。

但是講到這里還沒有結束,剛才并沒有嚴謹地說明坐標值到底是什么含義。一個整數坐標就是一個完整的格子嗎?那肯定不是,不然的話0和1之間豈不是沒有任何值了。上面在說具體的插值公式時我直接重新畫了一個圖2,暫時回避了這個問題。

現在再看看圖1,v11,v12,v21,v22對應的到底是哪4個點呢?下面的紅點分別是原圖上的(1.4, 1.4)和目標圖上的(2,2)。而4個黑點就是v11,v12,v21,v22

圖5

具體的坐標約定參照下圖,此圖來源于博客:

https://medium.com/@wenrudong/what-is-opencvs-inter-area-actually-doing-282a626a09b3

具體來說,每個像素格子的正中央就是整數坐標點,從(0,0)開始,下圖是一維的場景,二維也是一樣的道理。那么格子的邊框自然就是x.5了,比如0的左邊是-0.5,右邊是0.5(matlab中的約定跟opencv還不一樣,可能matlab中的整數坐標是從1開始的?暫時沒去了解matlab)

由上面的約定,我們就能確定目標圖上的點到原圖上的具體映射公式了,x坐標和y坐標的映射公式是一樣的,所以只說x。假設目標圖上的像素對應坐標為dx,求其映射回原圖的坐標sx。原圖的寬度除以目標圖的寬度的比值為scale,則:

sx=(dx+0.5)*scale-0.5? ? ------------------(式1)

這個式子是怎么來的?目標圖上的每個點都在原圖上有對應點

圖6

這是一個線性映射,故可以設sx=a*dx+b,再代入兩組具體的點就可以求解此方程:

1.dx=-0.5, sx=-0.5

2.dx=-0.5+1, sx=-0.5+scale (其實也可以不要第2組點,因為a就是scale!)

最終就能求出式1。平時我們直接用cv::resize的時候,可能并不需要知道這個公式,甚至在進行物體檢測后處理的時候,我們用目標圖上的物體框坐標,直接乘scale得到原圖物體框就行了,可能都不用嚴格按照上式(尤其是scale不太大的時候)。但是如果需要我們自己去實現插值邏輯,比如想在cuda中完成resize,以提升前處理的速度,那就需要用到這個式子了。

2.邊界值

現在考慮一下邊界情況,比如對于目標圖上的(0,0)點,計算出來的原圖坐標為(-0.14, -0.14),那它插值所需要的4個點就變成了(-1,-1),(-1,0), (0,-1),(0,0),問題是前三個點對應的像素根本就不存在啊。所以直接就用(0,0)這個點的像素值就行了。代碼實現上其實仍然是進行插值的,只不過插值前取點的時候,如果發現x坐標小于0了,修正為0,y坐標小于0了,也修正為0。

圖7

要說具體是怎么處理的,那肯定是直接上代碼最直接,下面截取了一段cv::hal::resize中的代碼,這段代碼就是在設置目標像素與原圖像素的映射關系與插值權重,這是x方向的。y方向的邏輯基本一樣。

另外說明一下,這段代碼中也包含了INTER_AREA的插值處理,不過是在scale小于1的時候,即放大圖片的時候,因為在放大圖片的時候,INTER_AREA最終調用的插值代碼跟INTER_LINEAR是一樣的,只不過它們的插值權重分配有區別。在“三。INTER_AREA”中會詳述

    for( dx = 0; dx < dsize.width; dx++ ){if( !area_mode ) // 非INTER_AREA,比如INTER_LINEAR, INTER_CUBIC,INTER_LANCZOS4{fx = (float)((dx+0.5)*scale_x - 0.5); // 目標圖像素坐標映射到原圖的浮點坐標sx = cvFloor(fx);fx -= sx;}else{sx = cvFloor(dx*scale_x); // INTER_AREA的像素坐標映射,向下取整fx = (float)((dx+1) - (sx+1)*inv_scale_x); //此式的后半部分是sx的右邊像素反映射到目標圖上的浮點坐標,記為fx1fx = fx <= 0 ? 0.f : fx - cvFloor(fx); //如果fx1在dx+1之前,說明dx其實也映射到sx+1上了,則會取兩個像素進行插值。否則直接取sx的像素值}if( sx < ksize2-1 ){xmin = dx+1; // 雙線性插值邏輯中其實沒用到xminif( sx < 0 && (interpolation != INTER_CUBIC && interpolation != INTER_LANCZOS4))fx = 0, sx = 0; // 1-fx是左邊元素權重,所以fx為0就是只取左邊元素,而sx就是左邊元素的坐標,所以就完成了左邊越界的處理。}if( sx + ksize2 >= src_width ){xmax = std::min( xmax, dx ); // 大于等于xmax的dx,只取左邊元素if( sx >= src_width-1 && (interpolation != INTER_CUBIC && interpolation != INTER_LANCZOS4))fx = 0, sx = src_width-1; // 原理其實跟上面一樣,右邊越界時,還是只取左邊元素。注意:sx本身沒有可能越右邊的界哦。}for( k = 0, sx *= cn; k < cn; k++ )xofs[dx*cn + k] = sx + k; // 目標圖像素與原圖像素映射關系(對于雙線性插值來說就是左邊的像素)if( interpolation == INTER_CUBIC )interpolateCubic( fx, cbuf );else if( interpolation == INTER_LANCZOS4 )interpolateLanczos4( fx, cbuf );else // INTER_LINEAR、INTER_AREA{cbuf[0] = 1.f - fx; // x軸方向左邊元素權重cbuf[1] = fx; // 右邊元素權重}// alpha就是x軸方向上每個目標圖像素對應到原圖的插值權重,對于INTER_LINEAR和INTER_AREA來說都是兩個像素,這邊只要權重,坐標的映射在前面的xofs里if( fixpt ) // 如果depth為CV_8U,則權重用的是short,而非float,最終插值的時候采用整數運算{for( k = 0; k < ksize; k++ ) // 先設第0個通道的權重ialpha[dx*cn*ksize + k] = saturate_cast<short>(cbuf[k]*INTER_RESIZE_COEF_SCALE); for( ; k < cn*ksize; k++ ) //其它通道的權重分配直接抄第0個通道就行了ialpha[dx*cn*ksize + k] = ialpha[dx*cn*ksize + k - ksize];}else{for( k = 0; k < ksize; k++ )alpha[dx*cn*ksize + k] = cbuf[k];for( ; k < cn*ksize; k++ )alpha[dx*cn*ksize + k] = alpha[dx*cn*ksize + k - ksize];}}

3.適用場景

平時就用INTER_LINEAR就好啦,那為什么下面還要介紹INTER_AREA呢,其實它兩適用的場景是不一樣的,放大圖片的時候用INTER_LINEAR比較好(如果想更好可以用INTER_CUBIC,但是計算量更大),但是縮小圖片就不一定了。

比如看下面這個例子,6乘6的圖,縮小為2乘2,scale為3

    scale = 3print([(dx+0.5)*scale-0.5 for dx in range(2)])img = np.array([[86, 85, 83, 92, 104, 127],[113, 105, 92, 103, 118, 135],[156, 137, 105, 121, 141, 147],[144, 138, 129, 148, 162, 130],[126, 135, 149, 168, 176, 108],[133, 132, 130, 138, 140, 85]], dtype=np.uint8)print(cv2.resize(img, (2, 2), interpolation=cv2.INTER_LINEAR))

輸出結果如下:

[1.0, 4.0]? ?----這就是由dx為0、1時計算出的sx,得到兩個整數,所以不會用到4個像素的值
[[105 118]? ? ? ?----分別對應原圖的(1,1), (1, 4)
?[135 176]]? ? ?-----分別對應原圖的(4,1), (4, 4)

映射圖如下,目標圖上每個像素都只用到原圖上一個像素,效果自然不會太好。

圖8

如果說剛才只是一個巧合,其實整體來說,縮小圖片時,如果縮小的比例比較大(即原圖尺度除以目標圖的比例),用INTER_LINEAR的效果就會打折扣。

比如現在是8乘8的圖,縮放到2乘2,如果仍然用INTER_LINEAR,則4個點映射關系如下,原圖和目標圖的對應點分別用了4種顏色,每個點都處在4個像素的邊框界限上,故其4周的4個像素正好可以取平均值,也就是說是正常插值的。但是再想想看,目標圖是2乘2,每一個像素其實對應在原圖上的區域是4乘4的區域(即16個像素),但插值只用了4個像素。所以說沒有充分利用到原圖上的像素。

圖9

那我怎樣才能用到原圖上的所有像素呢?就像上面的4個顏色的框子一樣?那就是下面要介紹的INTER_AREA了。

三。INTER_AREA

?INTER_AREA的映射邏輯跟INTER_LINEAR不一樣,INTER_LINEAR是點坐標映射,而?INTER_AREA更像是像素映射。并且INTER_AREA的代碼分了幾種情況進行處理。

1.整數倍縮放

其實圖9就是一個整數倍縮放的例子,比如原寬高是目標圖的iscale_x和iscale_y倍,則每目標圖中每一個像素必然對應原圖中的iscale_x*iscale_y個像素,并且目標圖上不同像素在原圖中的映射不會重疊,且總共會覆蓋到整個原圖。這很好理解,代碼處理起來也很簡單。最終把iscale_x*iscale_y個像素取個平均值就是縮放后的像素值,這就是INTER_AREA的fast流程。

這里再提一個特例,就是如果iscale_x和iscale_y都是2的話,opencv會調用fast的fast流程~~,因為4個像素取平均值通過移位操作就可以完成了,并且還用到了SIMD(單指令多數據),這個我暫時沒研究~~。另外,如果是INTER_LINEAR,并且也滿足iscale_x和iscale_y都是2的條件,那么實際上它的插值邏輯等階于INTER_AREA,所以它也會直接走INTER_AREA的fast的fast流程。

這里你可能有個疑問,我怎么通過代碼判斷是不是整數倍縮放呢?代碼如下,scale_x, scale_y是原圖寬高除以目標圖的寬高,類型為double,saturate_cast即cvRound,應該就類似于round()。

    int iscale_x = saturate_cast<int>(scale_x);int iscale_y = saturate_cast<int>(scale_y);bool is_area_fast = std::abs(scale_x - iscale_x) < DBL_EPSILON &&std::abs(scale_y - iscale_y) < DBL_EPSILON;
截取自《C語言程序設計:現代方法(第2版?修訂版)》

而DBL_EPSILON是double數的最小間隔數值,在我的gcc頭文件里看到的值為2.22044604925031308084726333618164062e-16L,注意,它可不是最小的double正值,它是不帶指數位的情況下可表示的兩個連續的double數之間的最小差值(或者說如下圖的注釋所說,是比1大的最小數與1的間隔)。要理解這個,需要先了解IEEE浮點標準。


截取自《數值分析 (Timothy Sauer 裴玉茹 馬賡宇)》

?所以DBL_EPSILON就是2的負52次方,即2.22E-16。那此處我們為什么通過它來判斷是否是整數呢?直接用DBL_MIN行不行呢?我也不能完全說上來【狗頭】。這個問題未必那么重要,如果scale和真正的整數已經是這么小的差異了,當成整數完全是沒有問題的,因為在”2.非整數倍縮放“中你會發現,這么小的差異已經被忽略了。

不過此處還是插入一段浮點數精確表示整數的分析(不感興趣的童鞋請跳過)。用下面這段代碼來看看float32是不是能表示所有的INT32。

void print_float(float a)
{unsigned int *ai = (unsigned int*)&a;unsigned int a_sign = *ai >> 31;unsigned int a_exp = (*ai >> 23) & ((1 << 8) - 1);unsigned int a_base = *ai & ((1 << 23) - 1);printf("a: %f, a_sign: %X, a_exp: %X, a_base: %X\n", a, a_sign, a_exp, a_base);}int main(int argc, char* argv[])
{float a;int error_count = 0;for (int i = 0; i < INT_MAX; i++){a = i;if (std::abs(a - i) > __FLT_EPSILON__ || std::abs(i - (int)a > 0)) // 為什么多加了一個條件,因為根本不存在16777217這個浮點數// if (std::abs(a - i) > FLT_MIN || std::abs(i - (int)a > 0)) // 其實是一樣的結果{printf("i: %d, ", i);print_float(a);if (error_count > 10){break;}error_count++;}}return 0;
}

運行結果如下:?

?

可以看到,從16777217開始,就不都能由float32精確表示了,其實原因很簡單?16777216的時候,由上圖可以看到,指數位為0x97,即151,減去指數偏移值127,得到24。尾數位為0,故最終的浮點值為1.0*(2^24)=16777216,其實2的24次方就是16777216。(為什么是1.0乘?因為IEEE標準默認尾數位是從1.X開始表示的,即小數點前面一定是1,這個1不用占用尾數位)。此時再讓它增加一個最小值,只能讓尾數最右位加1,最終整個浮點數加的值為:(2^-23)*(2^24)=2。所以只能得到16777218,跳過了16777217這個數。

所以就明白為什么16777216之前的整數都能精確表示出來了,因為在此之前,指數位m小于24,我始終能讓下一個數比上一個數大1,比如我在尾數位第n位加1(從左往右數的第n位),那么最終增加的值就是(2^-n)*(2^m),我只要讓n==m,加的值就是1!,而只要m小于24,我都能找到這個n。

不過有一點要注意的是,并不是說因為float32能表示16777216之前的所有整數,你就能用float32精確計算出16777216之前的所有scale,因為分子會比16777216更大啦。但是實際情況下往往也沒這么大的圖,也沒這么大的scale,所以float壓力都不大,double更加不是問題啦!

2.非整數倍縮放

非整數倍的縮放其實也是很簡單的,比如3乘3縮到2乘2,那目標圖上每個像素在原圖上會分到3/2乘3/2個像素,仍然是瓜分全圖的。不管是什么比例都能瓜分全圖,比如m乘m縮放到n乘n,那每個分m/n乘m/n,n*n*(m/n)*(m/n)=m*m。至于原圖各像素所占的權重,其實就是映射到它上面的面積。

圖10

可以看一個跨更多像素的例子,這里是12乘12的圖縮放到5乘5,縮放比例2.4,則目標圖上的(1,1)像素,對應原圖范圍為(2.4,2.4)到(4.8,4.8)的矩形范圍,一共占了9個像素,藍色的那個是完整覆蓋,其它的8個都只覆蓋了部分面積,覆蓋的9個像素的總面積為A(即2.4乘2.4),則計算目標像素時,每個原像素所占的權重就是它被覆蓋到的面積除以總面積A。

圖11

這里可能有個疑問,2.4為什么是下圖中的橙色點,而不是紅色點的位置?

圖12

目標圖上的(0,0)對應的肯定是原圖上的(0,0)到(2.4,2.4)的范圍吧,2.4就是scale,這樣就想明白了,所以說其實對于INTER_AREA來說,如果考慮浮點坐標,則左上角的起始坐標為(0,0),右下角的坐標為(12,12),前閉后開,(0,0)坐標能取到,(12,12)的坐標實際取不到。

圖13

3.放大

其實放大的插值原理跟“2.非整數倍縮放”是一樣的,但是既然是放大,目標圖在原圖上的覆蓋面積必然小于1,它有可能只會覆蓋到一個像素(覆蓋面在一個像素內),最多覆蓋4個像素(覆蓋面在4個像素交界處),這似乎跟雙線性插值有一點像,都是4個像素按權重求平均麻,所以說INTER_AREA的放大流程最終跟INTER_LINEAR調的是相同的函數,只是權重分配邏輯有區別,關于權重分配和像素映射的代碼參考“二。INTER_LINEAR”中的那段。

我們只把最關鍵的那段代碼再抄一遍:

sx = cvFloor(dx*scale_x); // INTER_AREA的像素坐標映射,向下取整//此式的后半部分是sx的右邊像素反映射到目標圖上的浮點坐標,記為fx1
fx = (float)((dx+1) - (sx+1)*inv_scale_x); //如果fx1在dx+1之前,說明dx其實也映射到sx+1上了,則會取兩個像素進行插值。否則直接取sx的像素值
fx = fx <= 0 ? 0.f : fx - cvFloor(fx); 

比如現在是5乘5的圖,放大到12乘12,scale為5/12,inv_scale就是12/5。為了方便展示,只畫x軸方向的圖。下圖演示的是目標圖dx=2像素,映射回原圖覆蓋的區域,映射回去的浮點值是0.83,向下取整得到sx為0,然后把sx+1反映射到目標圖上(就是綠色那條線),得到2.4,然后用dx+1(即2+1)減2.4,得到最終的fx=0.6,它就是原圖上sx+1所分配的權重,sx分配的權重自然就是1-fx=0.4。也就是說opencv如上的代碼,它其實是通過目標圖上的AB、BC段的比例來計算權重。不過其實AB和BC的比例與ab和bc的比例是一樣的,似乎在原圖上直接計算權重也沒問題。

圖14

?當然嘍,不是所有目標像素在原圖上都能覆蓋兩個像素(僅考慮x軸方向最多是2個像素,如果是二維的就是最多4個像素啦),比如考慮dx=1的像素,會發現C跑到B前面去了,那C-B就得到負值,按如上代碼的邏輯,fx取0,所以sx+1的權重為0。直觀理解也很明顯,ac段就是在原圖上覆蓋的區域,只覆蓋到了sx=0,自然只會取該像素值。

?再回顧一下剛才說直接在原圖上通過ab、bc的比例計算權重似乎也行,真的是這樣嗎?其實未必,因為在目標圖上,直接計算BC就能得出fx,不需要再除什么東西,因為AC的長度就是一個像素的長度,分母是1。但如果在原圖上計算,ac必然不是1,因為它就是scale啊,而放大的時候,scale必然小于1,所以得用bc/scale,bc經過了浮點計算,再拿它除浮點數,有可能造成誤差放大。

下面結合代碼再看一下,fx_opencv就是opencv中在目標圖上計算權重的方法,fx_my就是在原圖上計算權重,可以看到它最后要多除一個scale_x。

float fx_opencv(int dx, double scale_x, double inv_scale_x)
{int sx = cvFloor(dx * scale_x);float fx = (float)((dx + 1) - (sx + 1) * inv_scale_x);fx = fx <= 0 ? 0.f : fx - cvFloor(fx);return fx;
}float fx_my(int dx, double scale_x)
{float fx = dx * scale_x;int sx = cvFloor(fx);fx = fx + scale_x - (sx + 1);if (fx < 0){fx = 0.f;}else{fx /= scale_x;}return fx;
}int main(int argc, char* argv[])
{int src_width = 5, dest_width = 12;double scale = src_width / (double)dest_width;double inv_scale = 1 / scale;for (int i = 0; i < dest_width; i++){printf("i: %d, fx_opencv: %f, fx_my: %f\n", i, fx_opencv(i, scale, inv_scale), fx_my(i, scale));}return 0;
}

這次的結果倒是一樣,不過如果也許除法不如乘法快?暫時就不研究那么多了~~

另外如果是一切更特殊的數字,比如13放大到17,那結果還是有點差別的,不過也不大

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/65851.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/65851.shtml
英文地址,請注明出處:http://en.pswp.cn/web/65851.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

UnityDemo-TheBrave-制作筆記

這是我跟著b站up主MStudio的視頻學習制作的&#xff0c;大體上沒有去做一些更新的東西&#xff0c;這里只是一個總的總結。在文章的最后&#xff0c;我會放上可以游玩該游戲的鏈接和exe可執行文件&#xff0c;不過沒有對游戲內容進行什么加工&#xff0c;只有基本的功能實現罷了…

使用LSTM預測股票收盤價

在金融數據預測中&#xff0c;LSTM&#xff08;長短期記憶網絡&#xff09;憑借其在時間序列數據建模中的優勢&#xff0c;成為了分析股票價格趨勢的熱門選擇。本篇博客將以完整的代碼實現為例&#xff0c;展示如何利用LSTM網絡對股票收盤價進行預測&#xff0c;并從數據處理到…

模擬SpringIOCAOP

一、IOC容器 Ioc負責創建&#xff0c;管理實例&#xff0c;向使用者提供實例&#xff0c;ioc就像一個工廠一樣&#xff0c;稱之為Bean工廠 1.1 Bean工廠的作用 先分析一下Bean工廠應具備的行為 1、需要一個獲取實例的方法&#xff0c;根據一個參數獲取對應的實例 getBean(…

預編譯SQL

預編譯SQL 預編譯SQL是指在數據庫應用程序中&#xff0c;SQL語句在執行之前已經通過某種機制&#xff08;如預編譯器&#xff09;進行了解析、優化和準備&#xff0c;使得實際執行時可以直接使用優化后的執行計劃&#xff0c;而不需要每次都重新解析和編譯。這么說可能有一些抽…

Centos9 + Docker 安裝 MySQL8.4.0 + 定時備份數據庫到本地

Centos9 + Docker 安裝 MySQL8.4.0 + 定時備份數據庫到本地 創建目錄,創建配置文件啟動容器命令定時備份MySQL執行腳本Linux每日定時任務命令文件內參數其他時間參數AT一次性定時任務創建目錄,創建配置文件 $ mkdir -p /opt/mysql/conf$ vim /opt/mysql/conf/my.cnf[mysql] #…

軟件測試預備知識⑥—搭建Web服務器

在軟件測試的廣闊領域中&#xff0c;搭建Web服務器是一項極為關鍵的技能。它不僅有助于模擬真實的應用環境&#xff0c;方便我們對Web應用進行全面且深入的測試&#xff0c;還能讓測試人員更好地掌控測試場景&#xff0c;提升測試效率與質量。接下來&#xff0c;讓我們一同深入…

計算機視覺算法實戰——打電話行為檢測

?個人主頁歡迎您的訪問 ?期待您的三連 ? ?個人主頁歡迎您的訪問 ?期待您的三連 ? ?個人主頁歡迎您的訪問 ?期待您的三連? ??????? ??????????????? ?????? ? 1. 引言?? 隨著智能手機的普及&#xff0c;打電話行為檢測成為了計算機視…

事務的隔離級別和MDL

文章目錄 說明不同隔離級別可能發生的現象關鍵現象解釋MDL&#xff08;元數據鎖&#xff0c;Metadata Lock&#xff09;MDL 的作用MDL 的工作原理MDL 鎖的常見場景如何避免 MDL 阻塞 說明 本文章由大模型對話整理而來&#xff0c;如果有錯誤之處&#xff0c;請在評論區留言指正…

Linux第二課:LinuxC高級 學習記錄day01

0、大綱 0.1、Linux 軟件安裝&#xff0c;用戶管理&#xff0c;進程管理&#xff0c;shell 命令&#xff0c;硬鏈接和軟連接&#xff0c;解壓和壓縮&#xff0c;功能性語句&#xff0c;結構性語句&#xff0c;分文件&#xff0c;make工具&#xff0c;shell腳本 0.2、C高級 …

單片機存儲與計算機存儲:從微小到龐大的數據世界

單片機存儲與計算機存儲&#xff1a;從微小到龐大的數據世界 在現代電子設備中&#xff0c;存儲是至關重要的組成部分。無論是小巧的單片機&#xff0c;還是功能強大的計算機&#xff0c;存儲都扮演著不可或缺的角色。然而&#xff0c;單片機和計算機的存儲架構卻有著天壤之別…

ISP流程--去馬賽克詳解

前言 本期我們將深入討論ISP流程中的去馬賽克處理。我們熟知&#xff0c;彩色圖像由一個個像元組成&#xff0c;每個像元又由紅、綠、藍&#xff08;RGB&#xff09;三通道構成。而相機傳感器只能感知光的強度&#xff0c;無法直接感知光譜信息&#xff0c;即只有亮暗而沒有顏色…

阿里云-通義靈碼:在 PyCharm 中的強大助力(下)

目錄 六.通義靈碼在 PyCharm 中的優勢與不足 1.優勢 (1).提高開發效率 (2).提升代碼質量 (3).易于使用 (4).不斷學習和改進 2.不足 (1).依賴網絡 (2).準確性有待提高 (3).局限性 七.未來發展展望 1.提高準確性和可靠性 2.與其他工具的集成 3.智能化程度的提升 八…

開源項目stable-diffusion-webui部署及生成照片

參考鏈接 https://www.freedidi.com/13133.html 基礎環境部署 python 官網鏈接 Python Release Python 3.10.6 | Python.org 下載 Python 3.10.6 版本安裝包 下載好后雙擊 點擊安裝&#xff0c;這里需要選擇一下&#xff0c;把環境變量加上。&#xff08;這里是默認安裝到C盤…

【芯片封測學習專欄 -- 單 Die 與 多Die(Chiplet)介紹】

請閱讀【嵌入式開發學習必備專欄 Cache | MMU | AMBA BUS | CoreSight | Trace32 | CoreLink | ARM GCC | CSH】 文章目錄 Overview單個Die&#xff08;Monolithic Die&#xff09;多個Die&#xff08;Chiplet Architecture or Heterogeneous SoC&#xff09;如何判斷一個SoC是…

Windows 安裝 Docker 和 Docker Compose

&#x1f680; 作者主頁&#xff1a; 有來技術 &#x1f525; 開源項目&#xff1a; youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template &#x1f33a; 倉庫主頁&#xff1a; GitCode︱ Gitee ︱ Github &#x1f496; 歡迎點贊 &#x1f44d; 收藏 ?評論 …

java_將數據存入elasticsearch進行高效搜索

使用技術簡介&#xff1a; (1) 使用Nginx實現反向代理&#xff0c;使前端可以調用多個微服務 (2) 使用nacos將多個服務管理關聯起來 (3) 將數據存入elasticsearch進行高效搜索 (4) 使用消息隊列rabbitmq進行消息的傳遞 (5) 使用 openfeign 進行多個服務之間的api調用 參…

Github Copilot學習筆記

&#xff08;一&#xff09;Prompt Engineering 利用AI工具生成prompt設計好的prompt結構使用MarkDown語法&#xff0c;按Role, Skills, Constrains, Background, Requirements和Demo這幾個維度描述需求。然后收輸入提示詞&#xff1a;作為 [Role], 擁有 [Skills], 嚴格遵守 […

android分區和root

線刷包內容&#xff1a; 線刷包是一個完整的android鏡像&#xff0c;不但包括android、linux和用戶數據&#xff0c;還包括recovery等。當然此圖中沒有recovery,但是我們可以自己刷入一個。 主要分區 system.img 系統分區&#xff0c;包括linux下主要的二進制程序。 boot.img…

RabbitMQ基礎(簡單易懂)

RabbitMQ高級篇請看&#xff1a; RabbitMQ高級篇-CSDN博客 目錄 什么是RabbitMQ&#xff1f; MQ 的核心概念 1. RabbitMQ 的核心組件 2. Exchange 的類型 3. 數據流向說明 如何安裝RabbitQueue&#xff1f; WorkQueue&#xff08;工作隊列&#xff09;&#xff1a; Fa…

大數據環境搭建進度

1.使用虛擬機的系統&#xff1a;centos7.xLinux 2.資源不足&#xff0c;使用云服務器&#xff1a; 1. 3.使用遠程登錄進行操作 用xshell 4.任務 1.虛擬機裝好 2.設置IP地址 3.可以聯網 4.設置遠程登錄訪問 5.創建module和software目錄&#xff0c;修改兩…