原文来自ペラC、マシダF、ジュストDD。Sobel演算子[C] // IEEE International Conference on ImageProcessingに基づく画像のブロック性の評価。IEEE、2005年。
要約:この記事では、Sobel演算子を使用する、新しい非参照画像ブロッキング効果評価方法を提案します。ブロッキング効果スコアは、画像ブロックのエッジピクセルと中央ピクセルの輝度変化の組み合わせです。
詳細な方法:
-
画像IとSobel演算子のマスクMxとMyをそれぞれ
畳み込みます。Mx= [-1,0,1; -2,0,2; -1,0,1] My = [-1、-2、- 1; 0,0,0; 1,2,1]
エッジ画像DxおよびDyを取得します。Dx
= I Mx、Dy = I Myここで、「*」は畳み込み演算子を表します。 -
DxとDyをN * Nサイズの重複しないいくつかのブロックに分解します。ブロック効果がJpeg圧縮によって生成される場合、Nは8です。
-
各N * Nブロック(DxとDyによって分解されたブロック)に対して、次のセグメンテーションを実行します。
左から右への領域(図の灰色の部分)は、Ω1V、Ω1H、およびΩ2としてマークされます。つまり、各画像ブロックは次のようになります。最初と最後の列のすべてのピクセルはΩ1Vに属し、最初と最後の行のすべてのピクセルはΩ1Hに属し、2番目の行のすべてのピクセルは最後から2番目の行に、2番目の列から2番目の行に最後の列はΩ2に属します。 -
s1とs2は次のように定義されます。
ここで、N1とN2はそれぞれ右側の合計の長さ、つまり外側の円のピクセル数と内側の円のピクセル数です。 -
ブロック性指数S:
βは2を取ります。
Matlabの実装:
- まず、画像Iをグレースケール画像に変換します。すでにグレースケール画像である場合は、操作しないでください。
if numel(size(I))>2 %如果不为灰度图像
I=rgb2gray(I);
end
- conv2関数またはエッジを使用して、水平および垂直のエッジ画像dx、dy、および合計エッジ画像dを取得します。後続の操作の便宜のために、3つのエッジ画像はダブルタイプに変換されます。
dx=double(edge(I,'Sobel','horizontal'));
dy=double(edge(I,'Sobel','vertical'));
d=double(edge(I,'Sobel'));
- ブロッキング:lenxとlenyをブロックの高さと幅とします。デフォルト設定は8で、numは分割されたブロックの数を表し、初期値は0です。2層トラバーサルは、水平方向にlenyユニット、垂直方向にlenxユニットで実行されます。トラバーサルの終点は、の幅(サイズ(I、2))と高さ(サイズ(I、1))です。画像。現在の値iとjの垂直方向と水平方向のトラバースの場合、元の画像のブロックの左上のピクセルの位置は(i、j)、右下のピクセルは(xend、yen)、xendは高さですおよびi + lenx-1最小値、つまりブロックの最大高さはlenxに設定され、最小値は下部までの距離によって異なります(NNブロックのため、下部と右側のブロックはのサイズを満たさない場合があります。 NN)、そして同じことが円にも当てはまります。ブロックdx、dy、dの結果は構造Blockに格納されます。2レベルのトラバーサルの最後に、Blockの要素番号が変数numに設定されます。これは、ブロックの数として表されます。
lenx=8;
leny=8;
num=0;
for i=1:lenx:size(I,1)
for j=1:leny:size(I,2)
xend=min(i+lenx-1,size(I,1));
yend=min(j+leny-1,size(I,2));
num=num+1;
Block.images_dx{num}=dx(i:xend,j:yend);
Block.images_dy{num}=dy(i:xend,j:yend);
Block.images_d{num}=d(i:xend,j:yend);
end
end
Block.number=num;
4.水平、垂直、および内部ピクセルを取得します。例として水平エッジピクセルを取得し、関数get_h()を記述して、ブロック内の画像ブロックの水平エッジピクセルの座標を返します。最初に画像ブロックのサイズm * nを取得し、mが2以上の場合、2行(最初の行と最後の行)を返し、水平行列を2n(2つのピクセル数)に設定します。行)2、各行は2つのメタ座標です。1の場合は、行が1つしかないことを意味し、この行を返し、水平をn2に設定します。
最初に1からnをトラバースし、水平のi番目の行に座標(1、i)を格納します。mが2以上の場合は、引き続き格納します。iは1からnを再度トラバースし、座標
(n 、i)水平方向i + n番目の行。
function [horizontal]=get_h(dy)
[m,n]=size(dy);
if m>=2
horizontal=zeros(2*n,2);
else
horizontal=zeros(n,2);
end
for i=1:n
horizontal(i,1)=1;
horizontal(i,2)=i;
end
if m>=2
for i=1:n
horizontal(i+n,1)=n;
horizontal(i+n,2)=i;
end
end
end
同様に、垂直エッジピクセルの関数get_v()を記述します。内部ピクセルについては、画像ブロックのサイズm nが得られます。上下左右のピクセルはカウントされないため、内部ピクセル数は(m-2)(n-2)です。 。垂直方向と水平方向では、iとjはそれぞれ2からm-1(またはn-1)に移動し、結果のk番目の行は(i、j)になります。ここで、kは現在の座標数です。そして0に初期化されます。
function [inner]=get_inner(d)
[m,n]=size(d);
inner=zeros((m-2)*(n-2),2);
k=0;
for i=2:m-1
for j=2:n-1
k=k+1;
inner(k,1)=i;
inner(k,2)=j;
end
end
end
- 1からBlock.numberまでトラバースし、現在のi番目のdx、dy、dイメージブロック、つまりBlock.images_dx {i}をそれぞれ取得します。他の2つは同じです。前に記述した関数を呼び出し、ストレージを垂直にします。水平および内部ピクセル座標のマトリックスは、v、h、inで表されます。次に、N1はvの高さとhの高さの合計(2つの行列vとhに格納されているポイント値の合計)であり、N2はinの高さ(inに格納されているポイントの数)です。マトリックス)。現在のブロックの場合、s1とs2を0に初期化し、max_x、max_y、およびmax_inを現在のブロックBlock.images_dx {i}、Block.images_dy {i}、およびBlock.images_d {i}の最大値として使用します。jは、式に従ってvのすべての行をトラバースし、s1はabs(Block.images_dx {i}(v(j、1)、v(j、2)))/ max_xを累積し、hをトラバースします。 。最後に、s1の値をN1で除算してBlockのs1行列に保存し、s2の値をN2で除算してs2行列に保存します。
for i=1:Block.number
v=get_v(Block.images_dx{i});
h=get_h(Block.images_dy{i});
in=get_inner(Block.images_d{i});
N1=size(v,1)+size(h,1);
N2=size(in,1);
s1=0;
s2=0;
max_x=max(max(Block.images_dx{i}));
max_y=max(max(Block.images_dy{i}));
max_in=max(max(Block.images_d{i}));
for j=1:size(v,1)
s1=s1+abs(Block.images_dx{i}(v(j,1),v(j,2)))/max_x;
end
for j=1:size(h,1)
s1=s1+abs(Block.images_dy{i}(h(j,1),h(j,2)))/max_y;
end
for j=1:N2
s2=s2+abs(Block.images_d{i}(in(j,1),in(j,2)))/max_in;
end
Block.s1(i)=s1/N1;
Block.s2(i)=s2/N2;
end
- Sを計算する:まず、一部のブロックのN1またはN2が0であるため、ブロックのs1およびs2行列にNaN値があります。最初に、NaNの値を0に置き換えます:Block.s1(isnan(Block.s1 ))= 0;次に、s1とs2の平均値S1とS2を見つけ、最後に式に従ってSを見つけます。
Block.s1(isnan(Block.s1))=0;
Block.s2(isnan(Block.s2))=0;
S1=mean(Block.s1);
S2=mean(Block.s2);
lambda=2;
S=abs((S1^lambda-S2^lambda)/(S1^lambda+S2^lambda));
完全なコード:
I=imread('1.jpg');
if numel(size(I))>2
I=rgb2gray(I);
end
dx=double(edge(I,'Sobel','horizontal'));
dy=double(edge(I,'Sobel','vertical'));
d=double(edge(I,'Sobel'));
lenx=8;
leny=8;
num=0;
for i=1:lenx:size(I,1)
for j=1:leny:size(I,2)
xend=min(i+lenx-1,size(I,1));
yend=min(j+leny-1,size(I,2));
num=num+1;
Block.images_dx{num}=dx(i:xend,j:yend);
Block.images_dy{num}=dy(i:xend,j:yend);
Block.images_d{num}=d(i:xend,j:yend);
end
end
Block.number=num;
for i=1:Block.number
v=get_v(Block.images_dx{i});
h=get_h(Block.images_dy{i});
in=get_inner(Block.images_d{i});
N1=size(v,1)+size(h,1);
N2=size(in,1);
s1=0;
s2=0;
max_x=max(max(Block.images_dx{i}));
max_y=max(max(Block.images_dy{i}));
max_in=max(max(Block.images_d{i}));
for j=1:size(v,1)
s1=s1+abs(Block.images_dx{i}(v(j,1),v(j,2)))/max_x;
end
for j=1:size(h,1)
s1=s1+abs(Block.images_dy{i}(h(j,1),h(j,2)))/max_y;
end
for j=1:N2
s2=s2+abs(Block.images_d{i}(in(j,1),in(j,2)))/max_in;
end
Block.s1(i)=s1/N1;
Block.s2(i)=s2/N2;
end
Block.s1(isnan(Block.s1))=0;
Block.s2(isnan(Block.s2))=0;
S1=mean(Block.s1);
S2=mean(Block.s2);
lambda=2;
S=abs((S1^lambda-S2^lambda)/(S1^lambda+S2^lambda));
function [vertical]=get_v(dx)
[m,n]=size(dx);
if n>=2
vertical=zeros(2*m,2);
else
vertical=zeros(m,2);
end
for i=1:m
vertical(i,1)=i;
vertical(i,2)=1;
end
if n>=2
for i=1:m
vertical(i+m,1)=i;
vertical(i+m,2)=n;
end
end
end
function [horizontal]=get_h(dy)
[m,n]=size(dy);
if m>=2
horizontal=zeros(2*n,2);
else
horizontal=zeros(n,2);
end
for i=1:n
horizontal(i,1)=1;
horizontal(i,2)=i;
end
if m>=2
for i=1:n
horizontal(i+n,1)=n;
horizontal(i+n,2)=i;
end
end
end
function [inner]=get_inner(d)
[m,n]=size(d);
inner=zeros((m-2)*(n-2),2);
k=0;
for i=2:m-1
for j=2:n-1
k=k+1;
inner(k,1)=i;
inner(k,2)=j;
end
end
end