图像饱和度调整 参考

图像的饱和度调整有很多方法,最简单的就是判断每个象素的R、G、B值是否大于或小于128,大于加上调整值,小于则减去调整值;也可将象素RGB转换为HSV或者HSL,然后调整其S部分,从而达到线性调整图象饱和度的目的。这几种方法我都测试过,效果均不太好,简单的就不说了,利用HSV和HSL调整饱和度,其调节范围很窄,饱和度没达到,难看的色斑却出现了。而Photoshop的饱和度调整调节范围大多了,效果也好多了,请看下面25%饱和度调整时几种方法的效果对比图:

可以看出,都是25%的饱和度调整,Photoshop的调节幅度显得小一些(平坦些),效果也好多了,而HSV和HSL均出现了色斑,某些颜色也严重失真,尤其是HSV方式。

        据网上和书上的介绍,Photoshop的是利用所谓HSB颜色模式实现色相/饱和度调节的,可是就是没有看到其算法,我只得自己进行琢磨,首先发现Photoshop色相/饱和度命令中的明度调节好象是“独立”的,也就是它不需要转换为所谓的HSB模式,直接靠白色和黑色遮照层进行调节,具体原理和代码可看我写的《GDI+ 在Delphi程序的应用 -- 仿Photoshop的明度调整》一文。后来,却又发现Photoshop的饱和度调节好象是“半独立的”,什么意思呢?就是说Photoshop的色相/饱和度的调整还是转换为HSL颜色模式进行的,只是饱和度的增减调节却是“独立”于SHL模式的另外一套算法,如果不是需要HSL的S和L部分进行饱和度的上下限控制,它也和明度调整一样,可以独立进行!下面是我写的C++算法(只是随手写的算法,不是真正的运行代码):


inline  void SwapRGB( int &a,  int &b)
{
    a += b;
    b = a - b;
    a -= b;
}

     //  利用HSL模式求得颜色的S和L
     double rgbMax = R / 255;
     double rgbMin = G / 255;
     double rgbC = B / 255;
     if (rgbMax < rgbC)
        SwapRGB(rgbMax, rgbC);
     if (rgbMax < rgbMin)
        SwapRGB(rgbMax, rgbMin);
     if (rgbMin > rgbC)
        SwapRGB(rgbMin, rgbC);
     double delta = rgbMax - rgbMin;
     // 如果delta=0,S=0,所以不能调整饱和度
     if (delta == 0) return;
        
     double value = rgbMax + rgbMin;
     double S, L = value / 2;
     if (L < 0.5)
        S = delta / value;
     else
        S = delta  / (2 - value);
     //  具体的饱和度调整,sValue为饱和度增减量
    
//  如果增减量>0,饱和度呈级数增强,否则线性衰减
     if (sValue > 0)
    {
         //  如果增减量+S > 1,用S代替增减量,以控制饱和度的上限
        
//  否则取增减量的补数
        sValue = sValue + S >= 1? S : 1 - sValue;
         //  求倒数 - 1,实现级数增强
        sValue = 1 / sValue - 1;
    }
     //  L在此作饱和度下限控制
    R = R + (R - L * 255) * sValue;
    G = G + (G - L * 255) * sValue;
    B = B + (B - L * 255) * sValue;

        从上面的算法代码中可以看到,Photoshop的饱和度调整没有像HSV和HSL的饱和度调整那样,将S加上增减量重新计算,并将HSL转换回RGB,而只是取得了颜色的S、L作为上下限控制,对原有的RGB进行了“补丁”式的调节。

        下面是根据以上算法写的Delphi的BASM代码和GDI+调用的饱和度调整过程:

  1. type
  2.   // 与GDI+ TBitmapData结构兼容的图像数据结构
  3.   TImageData = packed record
  4.     Width: LongWord;         // 图像宽度
  5.     Height: LongWord;        // 图像高度
  6.     Stride: LongWord;        // 图像扫描线字节长度
  7.     PixelFormat: LongWord;   // 未使用
  8.     Scan0: Pointer;          // 图像数据地址
  9.     Reserved: LongWord;      // 保留
  10.   end;
  11.   PImageData = ^TImageData;
  12. // 获取TBitmap图像的TImageData数据结构,便于处理TBitmap图像
  13. function GetImageData(Bmp: TBitmap): TImageData;
  14. begin
  15.   Bmp.PixelFormat := pf32bit;
  16.   Result.Width := Bmp.Width;
  17.   Result.Height := Bmp.Height;
  18.   Result.Scan0 := Bmp.ScanLine[Bmp.Height - 1];
  19.   Result.Stride := Result.Width shl 2;
  20. //  Result.Stride := (((32 * Bmp.Width) + 31) and $ffffffe0) shr 3;
  21. end;
  1. // 图像饱和度调整。Value:(-255 - +255,没作范围检查)
  2. procedure Saturation(Data: TImageData; Value: Integer);
  3. asm
  4.     push    ebp
  5.     push    esi
  6.     push    edi
  7.     push    ebx
  8.     mov     edi, [eax + 16]// edi = Data.Scan0
  9.     mov     ecx, [eax + 4// ecx = Data.Width * Data.Height
  10.     imul    ecx, [eax]
  11.     mov     ebp, edx
  12.     cld
  13.   @PixelLoop:              // for (i = ecx - 1; i >= 0; i --)
  14.     dec     ecx            // {
  15.     js      @end
  16.     movzx   eax, [edi + 2]
  17.     movzx   ebx, [edi + 1]
  18.     movzx   esi, [edi]
  19.     cmp     esi, ebx
  20.     jge     @@1
  21.     xchg    esi, ebx
  22.   @@1:
  23.     cmp     esi, eax
  24.     jge     @@2
  25.     xchg    esi, eax
  26.   @@2:
  27.     cmp     ebx, eax
  28.     jle     @@3
  29.     mov     ebx, eax
  30.   @@3:
  31.     mov     eax, esi       //   delta = varMax - varMin
  32.     sub     eax, ebx       //   if (delta == 0)
  33.     jnz     @@4            //   {
  34.     add     edi, 4         //     edi += 4
  35.     jmp     @PixelLoop     //     continue
  36.   @@4:                     //   }
  37.     add     esi, ebx
  38.     mov     ebx, esi       //   ebx = varMax + varMin
  39.     shr     esi, 1         //   esi = L = (varMax + varMin) / 2
  40.     cmp     esi, 128
  41.     jl      @@5
  42.     neg     ebx            //   if (L >= 128) ebx = 510 - ebx
  43.     add     ebx, 510
  44.   @@5:
  45.     imul    eax, 255       //   eax = S = delta * 255 / ebx
  46.     cdq
  47.     div     ebx
  48.     mov     ebx, ebp       //   ebx = value
  49.     test    ebx, ebx       //   if (ebx > 0)
  50.     js      @@10           //   {
  51.     add     bl, al
  52.     jnc     @@6            //     if (ebx + S >= 255)
  53.     mov     ebx, eax       //       ebx = S
  54.     jmp     @@7
  55.   @@6:
  56.     mov     ebx, 255
  57.     sub     ebx, ebp       //     else ebx = 255 - value
  58.   @@7:
  59.     mov     eax, 65025     //     ebx = 65025 / ebx - 255
  60.     cdq
  61.     div     ebx
  62.     sub     eax, 255
  63.     mov     ebx, eax       //   }
  64.   @@10:
  65.     push    ebp
  66.     mov     ebp, 255
  67.     push    ecx
  68.     mov     ecx, 3
  69.   @RGBLoop:                //   for (j = 3; j > 0; j --)
  70.     movzx   eax, [edi]     //   {
  71.     push    eax
  72.     sub     eax, esi       //     rgb = rgb + (rgb - L) * ebx / 255
  73.     imul    eax, ebx
  74.     cdq
  75.     idiv    ebp
  76.     pop     edx
  77.     add     eax, edx
  78.     jns     @@11
  79.     xor     eax, eax       //     if (rgb < 0) rgb = 0
  80.     jmp     @@12
  81.   @@11:
  82.     cmp     eax, 255
  83.     jle     @@12
  84.     mov     eax, 255       //     else if (rgb > 255) rgb = 255
  85.   @@12:
  86.     stosb                  //     *edi ++ = rgb
  87.     loop    @RGBLoop       //   }
  88.     pop     ecx
  89.     pop     ebp
  90.     inc     edi            // edi ++
  91.     jmp     @PixelLoop     // }
  92.   @end:
  93.     pop     ebx
  94.     pop     edi
  95.     pop     esi
  96.     pop     ebp
  97. end;
  98. procedure GdipSaturation(Bmp: TGpBitmap; Value: Integer);
  99. var
  100.   Data: TBitmapData;
  101. begin
  102.   if Value = 0 then Exit;
  103.   Data := Bmp.LockBits(GpRect(00, Bmp.Width, Bmp.Height), [imRead, imWrite], pf32bppARGB);
  104.   try
  105.     Saturation(TImageData(Data), Value);
  106.   finally
  107.     Bmp.UnlockBits(Data);
  108.   end;
  109. end;
  110. procedure BitmapSaturation(Bmp: TBitmap; Value: Integer);
  111. begin
  112.   if Value <> 0 then
  113.     Saturation(GetImageData(Bmp), Value);
  114. end;

        具体的测试代码就不写了,有兴趣者可参考我的《GDI+ 在Delphi程序的应用 -- 线性调整图像亮度》、《GDI+ 在Delphi程序的应用 -- 图像卷积操作及高斯模糊》和《GDI+ 在Delphi程序的应用 -- 图像亮度/对比度调整》等文章,写出GDI+的TGpBitmap和Delphi的TBitmap的测试代码,其运行结果与Photoshop完全一样。  

  对于色相的调整,HSV、HSL和HSB都是相同的,不同的只是饱和度和亮度(明度)的调整,前天我已经写了《GDI+ 在Delphi程序的应用 -- 仿Photoshop的明度调整》,加上这篇饱和度算法文章,是否意味Photoshop的HSB算法完全破解了呢?不然,Photoshop的饱和度和明度调整独立使用时,确实是我说的那样,与Photoshop效果完全一样,但是放在一起进行调节就有区别了,这里有个谁先谁后的时机问题,和我前天写的《GDI+ 在Delphi程序的应用 -- 图像亮度/对比度调整》中对比度和亮度关系一样,各自独立使用没问题,放在一起调整就麻烦,但是对比度和亮度的关系比较简单,几次测试就清楚了,而饱和度和明度的关系我试验过多次,均与Photoshop有区别(只是有区别而以,其效果不比Photoshop的差多少),所以,要完全破解,还得试验,如果有谁知道,请务必告知,本人在此先谢了。下面干脆把我用BCB6写的试验性代码完整的贴在这,有兴趣的朋友可以帮忙试验,这个试验代码写的很零乱,运行也不快,先调整饱和度,再调整明度,其他方式没成功,所以没保存结果。

//  rgbhsb.h

#ifndef RgbHsbH
#define RgbHsbH

#include <windows.h>
#include <algorithm>
using std::min;
using std::max;
#include <gdiplus.h>
using  namespace Gdiplus;

void SetRgbHsb(unsigned  char &R, unsigned  char &G, unsigned  char &B,
                int hValue,  int sValue,  int bValue);
void GdipHSBAdjustment(Bitmap *Bmp,  int hValue,  int sValue,  int bValue);

// ---------------------------------------------------------------------------
#endif

//  rgbhsb.cpp

#pragma hdrstop

#include "RgbHsb.h"

// ---------------------------------------------------------------------------

inline  void SwapRGB( int &a,  int &b)
{
    a += b;
    b = a - b;
    a -= b;
}

inline  void CheckRGB( int &Value)
{
     if (Value < 0) Value = 0;
     else  if (Value > 255) Value = 255;
}

inline  void AssignRGB(unsigned  char &R, unsigned  char &G, unsigned  char &B,  int rv,  int gv,  int bv)
{
    R = rv;
    G = gv;
    B = bv;
}

void SetRgbHsb(unsigned  char &R, unsigned  char &G, unsigned  char &B,  int hValue,  int sValue,  int bValue)
{
     int rgbMax = R;
     int rgbMin = G;
     int rgbC = B;
     if (rgbMax < rgbC)
        SwapRGB(rgbMax, rgbC);
     if (rgbMax < rgbMin)
        SwapRGB(rgbMax, rgbMin);
     if (rgbMin > rgbC)
        SwapRGB(rgbMin, rgbC);
     int value = rgbMax + rgbMin;
     int L = (value + 1) >> 1;
     int H, S;
     int delta = rgbMax - rgbMin;
     if (!delta)
        H = S = 0;
     else
    {
         if (L < 128)
            S = delta * 255 / value;
         else
            S = delta * 255 / (510 - value);
         if (rgbMax == R)
            H = (G - B) * 60 / delta;
         else  if (rgbMax == G)
            H = (B - R) * 60 / delta + 120;
         else
            H = (R - G) * 60 / delta + 240;
         if (H < 0) H += 360;
         if (hValue)
        {
            H += hValue;
             if (H < 0) H += 360;
             else  if (H > 360) H -= 360;
             int m = H % 60;
            H /= 60;
             if (H & 1) m = 60 - m;
            rgbC = (m * 255 + 30) / 60;
            rgbC = rgbC - (rgbC - 128) * (255 - S) / 255;
             int Lum = L - 128;
             if (Lum > 0)
                rgbC = rgbC + ((255 - rgbC) * Lum + 64) / 128;
             else  if (Lum < 0)
                rgbC = rgbC + rgbC * Lum / 128;
        }
         else H /= 60;
         if (sValue)
        {
             if (sValue > 0)
            {
                sValue = sValue + S >= 255? S : 255 - sValue;
                sValue = 65025 / sValue - 255;
            }
            rgbMax = rgbMax + (rgbMax - L) * sValue / 255;
            rgbMin = rgbMin + (rgbMin - L) * sValue / 255;
            rgbC = rgbC + (rgbC - L) * sValue / 255;
        }
    }
     if (bValue > 0)
    {
        rgbMax = rgbMax + (255 - rgbMax) * bValue / 255;
        rgbMin = rgbMin + (255 - rgbMin) * bValue / 255;
        rgbC = rgbC + (255 - rgbC) * bValue / 255;
    }
     else  if (bValue < 0)
    {
        rgbMax = rgbMax + rgbMax * bValue / 255;
        rgbMin = rgbMin + rgbMin * bValue / 255;
        rgbC = rgbC + rgbC * bValue / 255;
    }
    CheckRGB(rgbMax);
    CheckRGB(rgbMin);
    CheckRGB(rgbC);
     if (bValue || S)
    {
         switch (H)
        {
           case 1: AssignRGB(R, G, B, rgbC, rgbMax, rgbMin);
           break;
           case 2: AssignRGB(R, G, B, rgbMin, rgbMax, rgbC);
           break;
           case 3: AssignRGB(R, G, B, rgbMin, rgbC, rgbMax);
           break;
           case 4: AssignRGB(R, G, B, rgbC, rgbMin, rgbMax);
           break;
           case 5: AssignRGB(R, G, B, rgbMax, rgbMin, rgbC);
           break;
           default:AssignRGB(R, G, B, rgbMax, rgbC, rgbMin);
        }
    }
//     else AssignRGB(R, G, B, rgbMax, rgbMin, rgbC);
}

void GdipHSBAdjustment(Bitmap *Bmp,  int hValue,  int sValue,  int bValue)
{
    sValue = sValue * 255 / 100;
    bValue = bValue * 255 / 100;
    BitmapData data;
    Rect r(0, 0, Bmp->GetWidth(), Bmp->GetHeight());
    Bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat24bppRGB, &data);
     try
    {
         int offset = data.Stride - data.Width * 3;
        unsigned  char *p = (unsigned  char*)data.Scan0;
         for ( int y = 0; y < data.Height; y ++, p += offset)
             for ( int x = 0; x < data.Width; x ++, p += 3)
                SetRgbHsb(p[2], p[1], *p, hValue, sValue, bValue);
    }
    __finally
    {
        Bmp->UnlockBits(&data);
    }
}

#pragma package(smart_init)

//  main.h

#ifndef mainH
#define mainH
// ---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
#include <ExtCtrls.hpp>
#include "RgbHsb.h"
// ---------------------------------------------------------------------------
class TForm1 :  public TForm
{
__published:     //  IDE-managed Components
    TButton *Button1;
    TLabel *Label1;
    TLabel *Label2;
    TLabel *Label3;
    TTrackBar *HBar;
    TTrackBar *SBar;
    TTrackBar *BBar;
    TEdit *HEdit;
    TEdit *SEdit;
    TEdit *BEdit;
    TPaintBox *PaintBox1;
     void __fastcall PaintBox1Paint(TObject *Sender);
     void __fastcall HEditKeyPress(TObject *Sender,  char &Key);
     void __fastcall HEditChange(TObject *Sender);
     void __fastcall HBarChange(TObject *Sender);
     void __fastcall SBarChange(TObject *Sender);
     void __fastcall BBarChange(TObject *Sender);
private:     //  User declarations
public:         //  User declarations
    __fastcall TForm1(TComponent* Owner);
    __fastcall ~TForm1( void);
};
// ---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
// ---------------------------------------------------------------------------
#endif

//  main.cpp


#include <vcl.h>
#pragma hdrstop

#include "main.h"
#include <stdlib.h>
// ---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

ULONG gdiplusToken;
Bitmap *Bmp, *tmpBmp;
Gdiplus::Rect r;
bool  lock;

// ---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    Bmp =  new Bitmap(WideString("100_0349.jpg" /* "d:/100_1.jpg" */));
    r = Gdiplus::Rect(0, 0, Bmp->GetWidth(), Bmp->GetHeight());
    tmpBmp = Bmp->Clone(r, PixelFormat24bppRGB);
    DoubleBuffered =  true;
     lock =  false;
}
__fastcall TForm1::~TForm1( void)
{
    delete tmpBmp;
    delete Bmp;
    GdiplusShutdown(gdiplusToken);
}
// ---------------------------------------------------------------------------


void __fastcall TForm1::PaintBox1Paint(TObject *Sender)
{
    Gdiplus::Graphics g(PaintBox1->Canvas->Handle);
    g.DrawImage(tmpBmp, r);
    g.TranslateTransform(0, r.Height);
    g.DrawImage(Bmp, r);
}
// ---------------------------------------------------------------------------

void __fastcall TForm1::HEditKeyPress(TObject *Sender,  char &Key)
{
     if (Key >= 32 && (Key < 48 || Key > 57))
        Key = 0;
}
// ---------------------------------------------------------------------------

void __fastcall TForm1::HEditChange(TObject *Sender)
{
     lock =  true;
     if (((TEdit*)Sender)->Text.Length() == 0)
        ((TEdit*)Sender)->Text = "0";
     switch (((TEdit*)Sender)->Tag)
    {
         case 0: HBar->Position = HEdit->Text.ToInt();
         break;
         case 1: SBar->Position = SEdit->Text.ToInt();
         break;
         case 2: BBar->Position = BEdit->Text.ToInt();
         break;
    }
     lock =  false;
    delete tmpBmp;
    tmpBmp = Bmp->Clone(r, PixelFormat24bppRGB);
     if (HBar->Position || SBar->Position || BBar->Position)
        GdipHSBAdjustment(tmpBmp, HBar->Position, SBar->Position, BBar->Position);
    PaintBox1->Invalidate();
}
// ---------------------------------------------------------------------------

void __fastcall TForm1::HBarChange(TObject *Sender)
{
     if (! lock)
        HEdit->Text = HBar->Position;
}
// ---------------------------------------------------------------------------

void __fastcall TForm1::SBarChange(TObject *Sender)
{
     if (! lock)
        SEdit->Text = SBar->Position;
}
// ---------------------------------------------------------------------------

void __fastcall TForm1::BBarChange(TObject *Sender)
{
     if (! lock)
        BEdit->Text = BBar->Position;
}

  由于本人文化水平太差,虽摸索出这些算法,但却没法把它进一步说透,只好说些“独立”,“补丁”的字眼,让各位见笑了。如有错误请指正,有建议也请来信:maozefa@hotmail.com

        后记:在GDI+下,32位PNG图像经转换为24位图像格式处理还原后,原有的透明色在转换过程中损失,故将本文对24位图像处理代码改为了32位图像处理代码。(2007.12.12)

   说明:为了统一《GDI+ 在Delphi程序的应用》系列文章所用数据类型和图像处理格式,本文代码已作了修订,代码中所用Gdiplus单元下载地址及BUG更正见文章《GDI+ for VCL基础 -- GDI+ 与 VCL》。(2008.8.18记)


转自http://blog.csdn.net/maozefa/article/details/1781208

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本书也是一本介绍图像技术的教材,但它有不同的视点和方式。至少有两点值得指出: 首先,作者完全采用了一种问答的形式来组织和介绍相关内容。全书从头到尾共设计了472个问题(很多是由学生提出来的),有问有答,循序渐进,逐步将各种图像技术依次介绍。这种形式除能帮助课堂教学外,也很适合自学,因为每一段都解决了一个疑问,对自学者会很有吸引力。书中还有383个详细的示例,不仅方便读者学习,对讲授相关课程的教师也是一个很好的资源。 其次,作者对基本内容和高级内容进行了划分。但与许多教材中这两部分内容不相重合、后者是前者的延伸不同,该书两部分内容密切相关、后者对应前者的更深层次。从其安排来看,基本内容是主干,而高级内容(放在63个框内,且有161个配合示例,编号前均加B)则分布在书中与相关基本内容对应的位置。如果把基本内容看作一个主程序,那么这些高级内容部分就像子程序,随时可在需要处调用。 本书是一本篇幅较大的书,从结构上看,有7章共27节。全书共有编了号的图307个(其中10个为彩图)、表格25个、公式1892个。另外有一个约80篇参考文献的目录,以及可进行索引的近400个术语。全书译成中文约合100万字(也包括图片、绘图、表格、公式等)。本书可作为已具有初步图像技术知识的相关专业高年级本科生和低年级研究生的专业基础课教材,也可供从事图像应用相关领域的科研技术人员参考。 译者基本忠实原书的结构和文字风格进行了翻译。为方便阅读,对书中问答中的问题按章节进行了编号。考虑到书中分散介绍了40多个具体算法,译文中归纳增加了一个算法列表。另外,对原书的索引,考虑中文的习惯进行了一些调整,并按中文次序进行了排列,希望能更好地服务于读者。 封面 -27 封底 -26 书名 -25 版权 -24 译者序 -19 前言 -18 目录 -16 第1章 导论 1 1.0.1 为什么要处理图像? 1 1.0.2 什么是一幅图像? 1 1.0.3 什么是一幅数字图像? 1 1.0.4 什么是一个光谱带? 1 1.0.5 为什么大多数图像处理算法都参照灰度图像进行,而实际中遇到的都是彩色图像? 2 1.0.6 一幅数字图像是如何形成的? 2 1.0.7 如果一个传感器对应物理世界中的一个小片,如何能让多个传感器对应场景中的同一个小片? 2 1.0.8 什么是图像中一个像素位置亮度的物理含义? 3 1.0.9 为什么图像常用512×512,256×256,128×128 等来表示? 4 1.0.10 需要多少个比特以存储一幅图像? 5 1.0.11 什么决定了一幅图像的质量? 5 1.0.12 什么会使得图像模糊? 5 1.0.13 图像分辨率是什么含义? 5 1.0.14 “良好对比度”是什么含义? 7 1.0.15 图像处理的目的是什么? 8 1.0.16 如何进行图像处理? 8 1.0.17 图像处理中使用非线性操作符吗? 9 1.0.18 什么是线性操作符? 9 1.0.19 如何来定义线性操作符? 9 1.0.20 一个成像装置的点扩散函数和一个线性操作符之间有什么联系? 9 1.0.21 一个线性操作符如何变换一幅图像? 9 1.0.22 点扩散函数的含义是什么? 10 B1.1 在连续空间中一个点源的正式定义 10 1.0.23 实际中如何描述一个线性操作符作用在一幅图像上的效果? 15 1.0.24 对一幅图像可使用多于一个线性操作符吗? 18 1.0.25 线性操作符使用的次序会导致结果的不同吗? 18 B1.2 因为矩阵运算次序是不能互换的,如果改变使用移不变线性操作符的次序会发生什么情况? 18 B1.3 什么是堆叠操作符? 24 1.0.26 对矩阵H结构上可分离性的假设意味着什么? 30 1.0.27 如何能将一个可分离变换写成矩阵的形式? 31 1.0.28 可分离性假设的含义是什么? 32 B1.4 可分离矩阵方程的正式推导 32 1.0.29 本章要点 34 1.0.30 式(1.108)在线性图像处理中的意义是什么? 34 1.0.31 这本书有些什么内容呢? 36 第2章 图像变换 37 2.0.1 本章概况 37 2.0.2 如何能定义一幅基本图像? 37 2.0.3 什么是两个矢量的外积? 37 2.0.4 如何可将一幅图像展开成矢量的外积? 37 2.0.5 如何选择矩阵hc和hr? 39 2.0.6 什么是酉矩阵? 39 2.0.7 酉矩阵的逆是什么样的? 39 2.0.8 如何能构建一个酉矩阵? 40 2.0.9 如何选择矩阵U和V以使表达g的比特数比f少? 40 2.0.10 什么是矩阵对角化? 40 2.0.11 可以对角化任何矩阵吗? 40 2.1 奇异值分解 40 2.1.1 如何能对角化一幅图像? 40 B2.1 可将任何图像都展开成矢量的外积吗? 43 2.1.2 如何计算图像对角化所需的矩阵U,V和Λ.? 44 B2.2 如果矩阵ggT 的本征值为负会如何? 44 2.1.3 什么是对一幅图像的奇异值分解? 47 2.1.4 能将一幅本征图像分解成多幅本征图像吗? 48 2.1.5 如何可用SVD 来近似一幅图像? 49 B2.3 SVD 的直观解释是什么? 49 2.1.6 什么是用SVD 近似一幅图像的误差? 50 2.1.7 如何能最小化重建误差? 51 2.1.8 任何图像都可以从某一组基本图像扩展出来吗? 56 2.1.9 什么是完备和正交的离散函数集合? 56 2.1.10 存在正交归一化离散值函数的完备集合吗? 57 2.2 哈尔、沃尔什和哈达玛变换 57 2.2.1 哈尔函数是如何定义的? 57 2.2.2 沃尔什函数是如何定义的? 57 B2.4 用拉德马赫函数定义的沃尔什函数 58 2.2.3 如何能用哈尔或沃尔什函数来生成图像基? 58 2.2.4 实际中如何用哈尔或沃尔什函数构建图像变换矩阵? 58 2.2.5 哈尔变换的基元图像看起来是什么样的? 61 2.2.6 可以定义元素仅为+1 或.1 的正交矩阵吗? 65 B2.5 对沃尔什函数的排列方式 65 2.2.7 哈达玛/沃尔什变换的基图像看起来是什么样的? 67 2.2.8 沃尔什和哈尔变换的优点和缺点各是什么? 69 2.2.9 什么是哈尔小波? 70 2.3 离散傅里叶变换 71 2.3.1 傅里叶变换的离散形式(DFT )是怎样的? 71 B2.6 离散傅里叶反变换是什么样的? 72 2.3.2 如何能将傅里叶变换写成矩阵形式? 72 2.3.3 用于DFT 的矩阵U是酉矩阵吗? 74 2.3.4 DFT 用来扩展图像的基元图像是什么样的? 76 2.3.5 为什么离散傅里叶变换比其他变换得到了更广泛的应用? 78 2.3.6 什么是卷积定理? 79 B2.7 如果一个函数是两个其他函数的卷积,它的DFT 与另两个函数的DFT 是什么关系? 79 2.3.7 如何显示一幅图像的离散傅里叶变换? 83 2.3.8 当图像旋转后其离散傅里叶变换将会怎么样? 84 2.3.9 当图像平移后其离散傅里叶变换将会怎么样? 85 2.3.10 图像的平均值与其DFT 有什么联系? 88 2.3.11 一幅图像放缩后其DFT 会如何变化? 89 B2.8 什么是快速傅里叶变换? 92 2.3.12 DFT 有哪些优点和缺点? 93 2.3.13 可以有实值的DFT 吗? 94 2.3.14 可以有纯虚部的DFT 吗? 96 2.3.15 一幅图像可以有纯实部或纯虚部值的DFT 吗? 101 2.4 偶对称离散余弦变换(EDCT) 101 2.4.1 什么是偶对称离散余弦变换? 101 B2.9 逆1-D 偶离散余弦变换的推导 106 2.4.2 2-D 时的逆偶余弦变换是怎样的? 107 2.4.3 用偶余弦变换扩展一幅图像时的基图像是怎样的? 107 2.5 奇对称离散余弦变换(ODCT) 109 2.5.1 什么是奇对称离散余弦变换? 109 B2.10 推导1-D 逆奇离散余弦变换 112 2.5.2 2-D 时的逆奇余弦变换是怎样的? 113 2.5.3 用奇余弦变换扩展一幅图像时的基图像是怎样的? 113 2.6 偶反对称离散正弦变换(EDST) 115 2.6.1 什么是偶反对称离散正弦变换? 115 B2.11 逆1-D 偶离散正弦变换的推导 118 2.6.2 2-D 时的逆偶正弦变换是怎样的? 119 2.6.3 用偶正弦变换扩展一幅图像时的基图像是怎样的? 119 2.6.4 如果在计算图像的EDST 前没有消除其均值会发生什么情况? 121 2.7 奇反对称离散正弦变换(ODST) 122 2.7.1 什么是奇反对称离散正弦变换? 122 B2.12 推导1-D 逆奇离散正弦变换 125 2.7.2 2-D 时的逆奇正弦变换是怎样的? 126 2.7.3 用奇正弦变换扩展一幅图像时的基图像是怎样的? 126 2.7.4 本章要点 128 第3章 图像的统计描述 130 3.0.1 本章概况 130 3.0.2 为什么需要对图像的统计描述? 130 3.1 随机场 130 3.1.1 什么是一个随机场? 130 3.1.2 什么是一个随机变量? 130 3.1.3 什么是一个随机试验? 131 3.1.4 如何用计算机做一个随机试验? 131 3.1.5 如何描述随机变量? 131 3.1.6 一个事件的概率是多少? 131 3.1.7 什么是一个随机变量的分布函数? 132 3.1.8 什么是一个随机变量取一个特殊值的概率? 133 3.1.9 什么是一个随机变量的概率密度函数? 133 3.1.10 如何描述许多随机变量? 134 3.1.11 n个随机变量互相之间有什么联系? 135 3.1.12 如何定义一个随机场? 138 3.1.13 如何能将在同一个随机场中的两个随机变量联系在一起? 139 3.1.14 如何能将在两个不同随机场中的两个随机变量联系在一起? 140 3.1.15 如果仅有系综图像中的一幅图像,可以计算期望值吗? 142 3.1.16 何时一个随机场相对于均值均匀? 142 3.1.17 何时一个随机场相对于自相关函数均匀? 142 3.1.18 如何计算一个随机场的空间统计? 143 3.1.19 实际中如何计算一幅图像随机场的空间自相关函数? 143 3.1.20 什么时候一个随机场相对于均值遍历? 144 3.1.21 什么时候一个随机场相对于自相关函数遍历? 144 3.1.22 什么是遍历性的含义? 145 B3.1 遍历性,模糊逻辑和概率理论 146 3.1.23 如何可以构建一个基元图像的基,从而用最优的方式描述完整的图像集合? 146 3.2 卡洛变换 147 3.2.1 什么是卡洛变换? 147 3.2.2 为什么一个图像集合的自协方差矩阵对角化定义了描述集合中图像所需的基? 147 3.2.3 如何变换一幅图像以使其自协方差矩阵成为对角的? 149 3.2.4 如果系综相对于自相关是平稳的,一组图像的系综自相关矩阵的形式是怎么样的? 154 3.2.5 如何根据一幅图像的矢量表达,从1-D 自相关函数得到其2-D 自相关矩阵? 155 3.2.6 如何能变换图像使其自相关矩阵成为对角的? 157 3.2.7 实际中如何计算一幅图像的卡洛变换? 158 3.2.8 如何计算系综图像的卡洛(K-L)变换? 158 3.2.9 遍历性假设切合实际吗? 158 B3.2 当一幅图像被表示成一个矢量时,如何计算该图像的空间自相关矩阵? 159 3.2.10 期望变换后图像的均值真正为0 吗? 162 3.2.11 如何能用一幅图像的卡洛变换来近似该图像? 162 3.2.12 将一幅图像的卡洛展开截断而近似该图像的误差是什么? 163 3.2.13 用卡洛变换展开一幅图像的基图像是什么样的? 163 B3.3 使用卡洛变换近似一幅图像的误差是多少? 167 3.3 独立分量分析 173 3.3.1 什么是独立分量分析(ICA)? 173 3.3.2 什么是鸡尾酒会问题? 174 3.3.3 如何解鸡尾酒会问题? 174 3.3.4 中心极限定理说些什么? 174 3.3.5 当讨论鸡尾酒会问题时说“x1(t)的采样比s1(t)或s2(t)的采样更趋向于高斯分布”是什么含义?是谈论x1(t)的时间采样还是谈论在给定时间x1(t)的所有可能版本? 174 3.3.6 如何测量非高斯性? 177 3.3.7 如何计算一个随机变量的矩? 178 3.3.8 峰度是如何定义的? 178 3.3.9 负熵是如何定义的? 180 3.3.10 熵是如何定义的? 180 B3.4 在所有方差相同的概率密度函数中,高斯函数具有最大的熵 182 3.3.11 如何计算负熵? 182 B3.5 用矩对负熵的近似推导 186 B3.6 用非二次函数近似负熵 187 B3.7 选择非二次函数以近似负熵 190 3.3.12 如何使用中心极限定理来解鸡尾酒会问题? 194 3.3.13 ICA 如何用于图像处理? 194 3.3.14 如何搜索独立分量? 195 3.3.15 如何白化数据? 196 3.3.16 如何从白化数据中选取独立分量? 196 B3.8 拉格朗日乘数法如何工作? 197 B3.9 如何选择一个能最大化负熵的方向? 198 3.3.17 实际中如何在图像处理中进行ICA? 202 3.3.18 如何将ICA 用于信号处理? 208 3.3.19 什么是独立分量分析的主要特点? 213 3.3.20 将ICA 应用于图像处理和信号处理有什么不同? 213 3.3.21 本章要点 213 第4章 图像增强 216 4.0.1 什么是图像增强? 216 4.0.2 如何能增强一幅图像? 216 4.0.3 什么是线性滤波器? 216 4.1 线性滤波器理论基础 216 4.1.1 如何定义一个2-D 滤波器? 216 4.1.2 频率响应函数和滤波器的单位采样响应是如何联系的? 217 4.1.3 为什么关心在实域中的滤波器函数? 217 4.1.4 h(k, l)需要满足什么条件才能用作卷积滤波器? 217 B4.1 2-D 理想低通滤波器的单位采样响应是什么样的? 218 4.1.5 1-D 和2-D 理想低通滤波器之间有什么联系? 221 4.1.6 如何可在实域中实现无穷延伸的滤波器? 222 B4.2 z-变换 222 4.1.7 可以为了方便而在实域中直接定义一个滤波器吗? 227 4.1.8 可以在实域中定义一个滤波器,但在频域中没有旁瓣吗? 228 4.2 消减高频噪声 228 4.2.1 一幅图像中会有什么种类的噪声? 228 4.2.2 什么是脉冲噪声? 228 4.2.3 什么是高斯噪声? 229 4.2.4 什么是加性噪声? 229 4.2.5 什么是乘性噪声? 229 4.2.6 什么是齐次噪声? 229 4.2.7 什么是零均值噪声? 229 4.2.8 什么是有偏噪声? 229 4.2.9 什么是独立噪声? 229 4.2.10 什么是不相关噪声? 230 4.2.11 什么是白噪声? 230 4.2.12 零均值不相关噪声与白噪声间有什么联系? 230 4.2.13 什么是iid 噪声? 231 4.2.14 可能有不是独立同分布的白噪声吗? 232 B4.3 一个随机变量的函数的概率密度函数 235 4.2.15 为什么噪声常与高频有关? 238 4.2.16 如何对待乘性噪声? 239 B4.4 德尔塔函数的傅里叶变换 239 B4.5 维纳-辛钦定理 239 4.2.17 对高斯噪声的假设在图像中合理吗? 240 4.2.18 如何消除散粒噪声? 240 4.2.19 什么是排序滤波器? 240 4.2.20 什么是中值滤波器? 240 4.2.21 什么是最频值滤波? 241 4.2.22 如何减小高斯噪声? 241 4.2.23 可以像加权平均滤波器那样对中值滤波器和最频值滤波器加权吗? 246 4.2.24 可以使用第2 章中的线性方法来对图像滤波吗? 247 4.2.25 如何处理图像中的混合噪声? 248 4.2.26 能在平滑图像时避免模糊它吗? 248 4.2.27 什么是边缘自适应平滑? 249 B4.6 有效计算局部方差 250 4.2.28 均移算法是如何工作的? 250 4.2.29 什么是非各向同性扩散? 252 B4.7 尺度空间和热力方程 252 B4.8 梯度,散度和拉普拉斯 253 B4.9 对一个积分相对于一个参数求导 255 B4.10 从热力学方程到非各向同性扩散算法 255 4.2.30 实际中如何实现非各向同性扩散? 256 4.3 消减低频干扰 257 4.3.1 什么时候会产生低频干扰? 257 4.3.2 变化的照明在高频也有体现吗? 257 4.3.3 还有哪些其他情况需要减少低频? 258 4.3.4 理想高通滤波器是什么样的? 258 4.3.5 如何用非线性滤波器来增强图像中的小细节? 262 4.3.6 什么是非锐化掩膜? 262 4.3.7 如何局部地使用非锐化掩膜算法? 263 4.3.8 局部自适应非锐化掩膜是如何工作的? 264 4.3.9 视网膜皮层理论算法是如何工作的? 265 B4.11 用视网膜皮层理论算法对哪些灰度值拉伸的最多? 266 4.3.10 如何增强受到变化照明影响的图像? 267 4.3.11 什么是同态滤波? 267 4.3.12 什么是光度立体视觉? 268 4.3.13 平场校正是什么意思? 268 4.3.14 平场校正是如何进行的? 268 4.4 直方图操作 269 4.4.1 什么是一幅图像的直方图? 269 4.4.2 什么时候需要改变图像的直方图? 269 4.4.3 如何改变一幅图像的直方图? 269 4.4.4 什么是直方图操作? 270 4.4.5 什么会影响一幅图像的语义信息内容? 270 4.4.6 如何能执行直方图操作并同时保留图像的信息内容? 270 4.4.7 什么是直方图均衡化? 271 4.4.8 为什么直方图均衡化程序一般并不产生具有平坦直方图的图像? 271 4.4.9 实际中如何进行直方图均衡化? 271 4.4.10 可能得到具有完全平坦直方图的图像吗? 273 4.4.11 如果不希望图像具有平坦的直方图应如何做? 273 4.4.12 实际中如何进行直方图双曲化? 273 4.4.13 如何结合随机加法进行直方图双曲化? 274 4.4.14 为什么在直方图均衡化外还需要其他处理? 275 4.4.15 如果图像具有不均匀的对比度怎么办? 275 4.4.16 可以在增加纯粹亮度过渡区的对比度时避免损坏平坦结构吗? 276 4.4.17 如何能通过仅拉伸纯粹亮度过渡区的灰度值来增强一幅图像? 277 4.4.18 实际中如何执行成对的图像增强? 278 4.5 通用去模糊算法 280 4.5.1 最频值滤波如何帮助去图像模糊? 281 4.5.2 可以在最频值滤波器中使用边缘自适应窗吗? 282 4.5.3 如何可使用均移作为通用的去模糊算法? 283 4.5.4 什么是滑降对比度增强? 283 4.5.5 实际中如何进行滑降对比度增强? 284 4.5.6 本章要点 287 第5章 图像恢复 290 5.0.1 什么是图像恢复? 290 5.0.2 为什么图像需要恢复? 290 5.0.3 什么是图像配准? 290 5.0.4 图像恢复是如何进行的? 290 5.0.5 图像增强和图像恢复的区别是什么? 290 5.1 齐次线性图像恢复:逆滤波 290 5.1.1 如何对齐次线性图像退化建模? 290 5.1.2 图像恢复问题可如何解决? 291 5.1.3 如何可以获得退化过程的频率响应函数H.(u, v)的信息? 291 5.1.4 如果已知退化过程的频率响应函数,解决图像恢复的问题是否很容易? 298 5.1.5 在频率响应函数为零处,频率会发生什么情况? 299 5.1.6 频率响应函数和图像的零点总相同吗? 299 5.1.7 如何避免噪声的放大? 299 5.1.8 实际中如何使用逆滤波? 301 5.1.9 可以定义一个自动考虑模糊图像中噪声的滤波器吗? 306 5.2 齐次线性图像恢复:维纳滤波 307 5.2.1 如何能将图像恢复问题描述成一个最小均方误差估计问题? 307 5.2.2 图像恢复问题有线性最小均方解吗? 307 5.2.3 什么是图像恢复问题的线性最小均方误差解? 308 B5.1 最小均方误差解 308 B5.2 从图像相关函数的傅里叶变换到它们的频谱密度 313 B5.3 维纳滤波器的推导 313 5.2.4 维纳滤波和逆滤波之间有什么联系? 314 5.2.5 如何确定噪声场的频谱密度? 315 5.2.6 如果不知道未知图像的统计特性,还有可能使用维纳滤波器吗? 315 5.2.7 实际中如何使用维纳滤波? 316 5.3 齐次线性图像恢复:约束矩阵求逆 319 5.3.1 如果假设退化过程是线性的,为什么要使用卷积定理而不通过解线性方程组来反演其效果? 319 5.3.2 式(5.146 )看起来非常直观,为什么还需要考虑其他方法? 320 5.3.3 有可以对矩阵H求逆的方法吗? 320 5.3.4 什么时候矩阵块轮换? 321 5.3.5 什么时候矩阵轮换? 321 5.3.6 为什么块轮换矩阵可以方便地求逆? 321 5.3.7 什么是一个轮换矩阵的本征值和本征矢量? 321 5.3.8 有关一个矩阵本征值和本征矢量的知识如何帮助对矩阵的求逆? 322 5.3.9 如何确定描述线性退化过程的矩阵H是块轮换的? 326 5.3.10 如何对角化一个块轮换矩阵? 327 B5.4 式(5.189)的证明 327 B5.5 矩阵H的转置是怎么样的? 328 5.3.11 如何克服矩阵求逆对噪声的极度敏感性? 334 5.3.12 如何将约束结合进矩阵的求逆? 335 B5.6 约束矩阵求逆滤波器的推导 338 5.3.13 维纳滤波器和约束矩阵求逆滤波器有什么联系? 339 5.3.14 实际中如何使用约束矩阵求逆? 341 5.4 非齐次线性图像恢复:旋转变换 344 5.4.1 如何对线性但非齐次的图像退化建模? 344 5.4.2 当退化矩阵不是轮换矩阵时如何使用约束矩阵求逆? 351 5.4.3 如果矩阵H非常大不能求逆怎么办? 353 B5.7 用于对大线性方程组求逆的雅克比法 354 B5.8 用于对大线性方程组求逆的高斯-赛德尔法 356 5.4.4 在例5.41、例5.43、例5.44 和例5.45 中构建的矩阵H满足使用高斯-赛德尔法或雅克比法的条件吗? 356 5.4.5 如果矩阵H不满足高斯-赛德尔法所需的条件会怎么样? 357 5.4.6 实际中如何使用梯度下降算法? 358 5.4.7 如果不知道矩阵H怎么办? 359 5.5 非线性图像恢复:MAP 估计 359 5.5.1 MAP 估计是什么意思? 359 5.5.2 如何将图像恢复问题公式化为一个MAP 估计问题? 360 5.5.3 给定退化模型和退化图像如何选择最可能的恢复像素值的组合? 360 B5.9 概率:先验,后验,条件 360 5.5.4 代价函数的最小值是唯一的吗? 361 5.5.5 如何从能最小化代价函数的所有可能解中选出一个来? 361 5.5.6 可以对一个组态x结合后验和先验概率吗? 362 B5.10 巴斯维尔定理 364 5.5.7 一般如何模型化需要最小化以恢复图像的代价函数? 366 5.5.8 当模型化联合概率密度函数时,温度参数并不改变概率取最大值的组态,那为什么要使用它? 367 5.5.9 温度参数是如何在解空间中允许聚焦或离焦的? 367 5.5.10 如何模型化组态的先验概率? 368 5.5.11 如果图像具有真正的不连续性会发生什么情况? 368 5.5.12 如何最小化代价函数? 369 5.5.13 如何从前一个解构建一个可能的新解? 369 5.5.14 如何知道何时停止迭代? 371 5.5.15 在模拟退火中如何减小温度? 371 5.5.16 实际中如何利用重要中心采样器进行模拟退火? 371 5.5.17 实际中如何利用吉伯斯采样器进行模拟退火? 372 B5.11 如何根据给定的概率密度函数取出一个随机数? 373 5.5.18 为什么模拟退火很慢? 375 5.5.19 如何能加快模拟退火? 375 5.5.20 如何能粗化组态空间? 376 5.6 几何图像恢复 376 5.6.1 如何会产生几何失真? 376 5.6.2 为什么镜头会导致失真? 377 5.6.3 如何恢复一幅几何失真的图像? 377 5.6.4 如何执行空间变换? 377 5.6.5 如何模型化镜头失真? 377 5.6.6 如何模型化非均匀失真? 379 5.6.7 如何确定空间变换模型的参数? 379 5.6.8 为什么需要灰度插值? 379 B5.12 检测线的哈夫变换 382 5.6.9 本章要点 386 第6章 图像分割和边缘检测 388 6.0.1 本章概况 388 6.0.2 图像分割和边缘检测的准确目的是什么? 388 6.1 图像分割 388 6.1.1 如何将一幅图像分成均匀的区域? 388 6.1.2 “标记”一幅图像是什么含义? 388 6.1.3 如果直方图中的谷没有被很明确地定义应怎么办? 389 6.1.4 如何最小化误分像素的数量? 389 6.1.5 如何选择最小误差阈值? 390 6.1.6 什么是目标和背景像素正态分布时的最小误差阈值? 393 6.1.7 什么是最小误差阈值方程两个解的含义? 394 6.1.8 如何估计代表目标和背景的高斯概率密度函数的参数? 395 6.1.9 最小误差阈值化方法的缺点是什么? 398 6.1.10 有能不依赖于目标和背景像素分布模型的方法吗? 398 B6.1 大津方法的推导 399 6.1.11 大津方法有什么缺点吗? 401 6.1.12 如何能对在照明变化的场合下获得的图像取阈值? 402 6.1.13 如果根据lnf(x, y)的直方图来对图像取阈值,是根据成像表面的反射性质来阈值化吗? 402 B6.2 两个随机变量和的概率密度函数 402 6.1.14 如何解决照明变化情况下直接阈值化算法会失败的问题? 403 6.1.15 如果直方图只有一个峰应怎么办? 404 6.1.16 灰度阈值化方法有什么缺点吗? 405 6.1.17 如何分割包含不均匀但感觉均匀区域的图像? 406 6.1.18 可以通过考虑像素的空间接近度来改进直方图化方法吗? 408 6.1.19 有考虑像素空间接近度的分割方法吗? 408 6.1.20 如何选择种子像素? 408 6.1.21 分裂和合并法如何工作? 409 6.1.22 什么是形态学图像重建? 409 6.1.23 如何用形态学图像重建确定水线算法所需的种子? 411 6.1.24 如何计算梯度幅度图? 411 6.1.25 在用g对f的形态学重建中,为生成模板g而从f中减去的数起什么作用? 412 6.1.26 结构元素的形状和尺寸在用g对f的形态学重建中起什么作用? 413 6.1.27 如何使用梯度幅度图像以帮助用水线算法分割图像? 419 6.1.28 在水线算法中使用梯度幅度图像有什么缺点吗? 419 6.1.29 可以用滤波来分割图像吗? 424 6.1.30 如何使用均移算法去分割图像? 424 6.1.31 什么是一个图? 425 6.1.32 能用一个图表示一幅图像吗? 425 6.1.33 如何借助一幅图像的图表达来分割它? 425 6.1.34 什么是归一化割算法? 426 B6.3 归一化割算法作为一个本征值问题 426 B6.4 如何最小化瑞利商? 433 6.1.35 实际中如何使用归一化图割算法? 435 6.1.36 与考虑像素间的相似性相对,可以通过考虑区域间的不相似性来分割图像吗? 436 6.2 边缘检测 436 6.2.1 如何测量相邻像素间的不相似性? 436 6.2.2 什么是最小可选的窗? 437 6.2.3 当图像中有噪声时会怎么样? 438 B6.5 如何选择用于边缘检测的3×3 模板的权重? 439 6.2.4 参数K的最优值是什么? 440 B6.6 索贝尔滤波器的推导 440 6.2.5 在通常情况下,如何确定一个像素是否为边缘像素呢? 444 6.2.6 实际中如何执行线性边缘检测? 445 6.2.7 索贝尔模板对所有图像都合用吗? 448 6.2.8 如果由于图像中有很显著的噪声而需要一个较大的模板, 如何选择模板的权重? 448 6.2.9 可以使用对边缘的最优滤波器以一种最优方式检测图像中的直线吗? 450 6.2.10 什么是阶跃边缘和直线间的基本差别? 450 B6.7 将一个随机噪声与一个滤波器卷积 454 B6.8 将一个有噪边缘信号与一个滤波器卷积后的信噪比计算 455 B6.9 良好局部性测度的推导 455 B6.10 虚假极值计数的推导 457 6.2.11 边缘检测能导致图像分割吗? 458 6.2.12 什么是滞后边缘连接? 458 6.2.13 滞后边缘连接能导致封闭的边缘轮廓吗? 459 6.2.14 什么是拉普拉斯-高斯边缘检测法? 460 6.2.15 有可能同时检测边缘和直线吗? 461 6.3 相位一致性和单基因信号 461 6.3.1 什么是相位一致性? 461 6.3.2 什么是1-D 数字信号的相位一致性? 462 6.3.3 如何能借助相位一致性检测直线和边缘? 462 6.3.4 为什么相位一致性与信号的局部能量最大值重合? 462 6.3.5 如何测量相位一致性? 463 6.3.6 能否简单地平均谐波分量的相位来测量相位一致性? 463 6.3.7 实际中如何测量相位一致性? 465 6.3.8 如何测量信号的局部能量? 466 6.3.9 为什么需要与两个基信号卷积以得到局部信号在基信号上的投影? 467 B6.11 连续傅里叶变换的一些性质 470 6.3.10 如果只需计算信号的局部能量,为什么不在实域的局部窗口中用帕赛瓦尔定理来计算? 477 6.3.11 如何决定使用哪个滤波器计算局部能量? 478 6.3.12 实际中如何计算一个1-D 信号的局部能量? 481 6.3.13 如何能判断局部能量的最大值对应一个对称或反对称的特征? 481 6.3.14 如何计算2-D 时的相位一致性和局部能量? 487 6.3.15 什么是解析信号? 487 6.3.16 如何推广希尔伯特变换到2-D? 487 6.3.17 如何计算一幅图像的里斯变换? 487 6.3.18 如何使用单基因信号? 488 6.3.19 如何选择要使用的偶滤波器? 488 6.3.20 本章要点 493 第7章 多光谱图像处理 495 7.0.1 什么是多光谱图像? 495 7.0.2 多光谱图像有哪些特殊的问题? 495 7.0.3 本章概述 496 7.1 多光谱图像处理 496 7.1.1 为什么会希望用其他带来替换多光谱图像的带? 496 7.1.2 一般如何从多光谱图像构建一幅灰度图像? 496 7.1.3 如何从一幅包含最大量图像信息的多光谱图像构建单个带? 496 7.1.4 什么是主分量分析? 497 B7.1 如何测量信息? 497 7.1.5 实际中如何进行主分量分析? 498 7.1.6 使用一幅图像的主分量而不是原始带的优点是什么? 499 7.1.7 使用一幅图像的主分量而不是原始带的缺点是什么? 499 7.1.8 如果对其他分量不感兴趣,有可能仅计算出一幅多光谱图像的第1 个主分量吗? 504 B7.2 用于估计一个矩阵的最大本征值的功率法 504 7.1.9 什么是光谱恒常性问题? 506 7.1.10 什么影响一个像素的光谱标记? 506 7.1.11 什么是反射函数? 506 7.1.12 成像几何影响一个像素的光谱标记吗? 506 7.1.13 成像几何如何影响一个像素所接收的光能量? 506 7.1.14 如何对朗伯表面的成像过程建模? 507 7.1.15 如何能消除一个像素的光谱对成像几何的依赖性? 507 7.1.16 如何能消除一个像素的光谱对照明源光谱的依赖性? 507 7.1.17 如果有不止一个照明源会发生什么情况? 508 7.1.18 如何能消除一个像素的光谱标记对成像几何和照明光谱的依赖性? 508 7.1.19 如果成像表面不是由相同材料构成时怎么办? 509 7.1.20 什么是光谱分解问题? 509 7.1.21 如何解决线性光谱分解问题? 510 7.1.22 可以对纯材料使用光谱库吗? 510 7.1.23 当已知纯分量的光谱时如何解线性光谱分解问题? 510 7.1.24 有可能不计算矩阵Q的逆吗? 513 7.1.25 如果库光谱是在与混合光谱不同的波长进行的采样会发生什么问题? 513 7.1.26 如果不知道在混合物质中有哪些纯物质可能存在会发生什么问题? 514 7.1.27 如果不知道纯材料的光谱如何解线性光谱分解问题? 515 7.2 彩色视觉的物理学和心理物理学 518 7.2.1 什么是彩色? 518 7.2.2 从工程的观点看彩色有什么感兴趣的地方? 518 7.2.3 哪些因素影响从一个暗物体感知到的彩色? 519 7.2.4 什么导致日光的变化? 520 7.2.5 如何能模型化日光的变化? 520 B7.3 标准光源 522 7.2.6 什么是天然材料的观测变化? 523 7.2.7 一旦光线到达传感器会发生什么情况? 529 7.2.8 一个传感器有可能对不同的材料产生相同的记录吗? 530 7.2.9 人类视觉系统是如何实现彩色恒常性的? 531 7.2.10 彩色视觉的三基色理论讲了什么? 531 7.2.11 用什么来定义一个彩色系统? 531 7.2.12 三刺激值是如何确定的? 531 7.2.13 所有的单色参考刺激都可以通过简单调节基色光的强度来匹配吗? 532 7.2.14 所有人都需要相同强度的基色光以匹配同样的单色参考刺激吗? 533 7.2.15 谁是具有正常彩色视觉的人? 533 7.2.16 什么是最常使用的彩色系统? 533 7.2.17 什么是CIE-RGB 彩色系统? 533 7.2.18 什么是XYZ 彩色系统? 534 7.2.19 如何在3-D 空间中表达彩色? 534 7.2.20 如何在2-D 空间中表达彩色? 534 7.2.21 什么是色度图? 535 B7.4 一些3-D 几何中有用的定理 536 7.2.22 CIE-RGB 彩色系统中的色度图是什么样的? 538 7.2.23 人的大脑是如何感知彩色强度的? 539 7.2.24 在CIE-RGB 彩色系统中是如何定义零发光线的呢? 539 7.2.25 XYZ 彩色系统是如何定义的? 540 7.2.26 XYZ 彩色系统中的色度图是什么样的? 542 7.2.27 实际中可能用虚的基色生成一个彩色系统吗? 542 7.2.28 如何模型化一个特定人观察彩色的方式? 542 7.2.29 如果不同的观察者需要不同强度的基色光以看到白色,如何在不同观察者间校正彩色? 543 7.2.30 如何使用参考白色? 543 7.2.31 sRGB 彩色系统是如何定义的? 544 7.2.32 如果将一个彩色的所有三刺激值都翻倍它会变化吗? 545 7.2.33 用彩色系统的语言对一个彩色的描述与用日常语言的描述有什么联系? 545 7.2.34 如何比较彩色? 545 7.2.35 什么是一个测度? 545 7.2.36 能用欧氏测度来测量两个彩色的差别吗? 546 7.2.37 哪些是感知均匀的彩色空间? 546 7.2.38 Luv彩色空间是如何定义的? 546 7.2.39 Lab彩色空间是如何定义的? 547 7.2.40 如何选择(Xn, Yn, Zn)的值? 547 7.2.41 如何从Luv的值计算RGB 的值? 548 7.2.42 如何从Lab的值计算RGB 的值? 548 7.2.43 如何测量感知的饱和度? 549 7.2.44 如何测量饱和度感知的差别? 549 7.2.45 如何测量感知的色调? 549 7.2.46 色调角是如何定义的? 549 7.2.47 如何测量色调感知的差别? 550 7.2.48 什么影响人感知彩色的方式? 551 7.2.49 彩色的时间上下文是什么意思? 551 7.2.50 彩色的空间上下文是什么意思? 551 7.2.51 为什么当谈论空间频率时与距离有关系? 552 7.2.52 如何解释对彩色感知的空间依赖性? 552 7.3 实用彩色图像处理 553 7.3.1 对人类彩色视觉的研究如何影响进行图像处理的方式? 553 7.3.2 感知均匀彩色空间实际中有多感知均匀? 553 7.3.3 应如何将图像的RGB 值转换到Luv或Lab彩色空间中? 553 7.3.4 在图像处理应用中如何测量色调和饱和度? 557 7.3.5 如何能在图像处理中模仿彩色感知的空间依赖性? 561 7.3.6 同色异谱现象图像处理有什么联系? 563 7.3.7 如何解决一个工业监视应用中的同色异谱问题? 564 7.3.8 什么是蒙特卡洛方法? 565 7.3.9 如何从多光谱图像中消除噪声? 566 7.3.10 如何对矢量排序? 566 7.3.11 如何处理多光谱图像中的混合噪声? 567 7.3.12 如何增强一幅彩色图像? 568 7.3.13 如何恢复多光谱图像? 572 7.3.14 如何压缩彩色图像? 572 7.3.15 如何分割多光谱图像? 572 7.3.16 实际中如何使用k-均值聚类方法? 573 7.3.17 如何提取多光谱图像的边缘? 574 7.3.18 本章要点 574 附录A 算法列表 576 附录B 参考文献注解 578 附录C 参考文献 580 附录D 索引 584
1. 直方图均衡化的 Matlab 实现 1.1 imhist 函数 功能:计算和显示图像的色彩直方图 格式:imhist(I,n) imhist(X,map) 说明:imhist(I,n) 其中,n 为指定的灰度级数目,缺省值为256;imhist(X,map) 就算和显示索引色图像 X 的直方图,map 为调色板。用 stem(x,counts) 同样可以显示直方图。 1.2 imcontour 函数 功能:显示图像的等灰度值图 格式:imcontour(I,n),imcontour(I,v) 说明:n 为灰度级的个数,v 是有用户指定所选的等灰度级向量。 1.3 imadjust 函数 功能:通过直方图变换调整对比度 格式:J=imadjust(I,[low high],[bottom top],gamma) newmap=imadjust(map,[low high],[bottom top],gamma) 说明:J=imadjust(I,[low high],[bottom top],gamma) 其中,gamma 为校正量r,[low high] 为原图像中要变换的灰度范围,[bottom top] 指定了变换后的灰度范围;newmap=imadjust(map,[low high],[bottom top],gamma) 调整索引色图像的调色板 map 。此时若 [low high] 和 [bottom top] 都为2×3的矩阵,则分别调整 R、G、B 3个分量。 1.4 histeq 函数 功能:直方图均衡化 格式:J=histeq(I,hgram) J=histeq(I,n) [J,T]=histeq(I,...) newmap=histeq(X,map,hgram) newmap=histeq(X,map) [new,T]=histeq(X,...) 说明:J=histeq(I,hgram) 实现了所谓“直方图规定化”,即将原是图象 I 的直方图变换成用户指定的向量 hgram 。hgram 中的每一个元素 都在 [0,1] 中;J=histeq(I,n) 指定均衡化后的灰度级数 n ,缺省值为 64;[J,T]=histeq(I,...) 返回从能将图像 I 的灰度直方图变换成 图像 J 的直方图的变换 T ;newmap=histeq(X,map) 和 [new,T]=histeq(X,...) 是针对索引色图像调色板的直方图均衡。 2. 噪声及其噪声的 Matlab 实现 imnoise 函数 格式:J=imnoise(I,type) J=imnoise(I,type,parameter) 说明:J=imnoise(I,type) 返回对图像 I 添加典型噪声后的有噪图像 J ,参数 type 和 parameter 用于确定噪声的类型和相应的参数。 3. 图像滤波的 Matlab 实现 3.1 conv2 函数 功能:计算二维卷积 格式:C=conv2(A,B) C=conv2(Hcol,Hrow,A) C=conv2(...,'shape') 说明:对于 C=conv2(A,B) ,conv2 的算矩阵 A 和 B 的卷积,若 [Ma,Na]=size(A), [Mb,Nb]=size(B), 则 size(C)=[Ma+Mb-1,Na+Nb-1]; C=conv2(Hcol,Hrow,A) 中,矩阵 A 分别与 Hcol 向量在列方向和 Hrow 向量在行方向上进行卷积;C=conv2(...,'shape') 用来指定 conv2 返回二维卷积结果部分,参数 shape 可取值如下: 》full 为缺省值,返回二维卷积的全部结果; 》same 返回二维卷积结果中与 A 大小相同的中间部分; valid 返回在卷积过程中,未使用边缘补 0 部分进行计算的卷积结果部分,当 size(A)>size(B) 时,size(C)=[Ma-Mb+1,Na-Nb+1] 。 3.2 conv 函数 功能:计算多维卷积 格式:与 conv2 函数相同 3.3 filter2函数 功能:计算二维线型数字滤波,它与函数 fspecial 连用 格式:Y=filter2(B,X) Y=filter2(B,X,'shape') 说明:对于 Y=filter2(B,X) ,filter2 使用矩阵 B 中的二维 FIR 滤波器对数据 X 进行滤波,结果 Y 是通过二维互相关计算出来的,其大 小与 X 一样;对于 Y=filter2(B,X,'shape') ,filter2 返回的 Y 是通过二维互相关计算出来的,其大小由参数 shape 确定,其取值如下 : 》full 返回二维相关的全部结果,size(Y)>size(X); 》same 返回二维互相关结果的中间部分,Y 与 X 大小相同; 》valid 返回在二维互相关过程中,未使用边缘补 0 部分进行计算的结果部分,有 size(Y)<size(X) 。 3.4 fspecial 函数 功能:产生预定义滤波器 格式:H=fspecial(type) H=fspecial('gaussian',n,sigma) 高斯低通滤波器 H=fspecial('sobel') Sobel 水平边缘增强滤波器 H=fspecial('prewitt') Prewitt 水平边缘增强滤波器 H=fspecial('laplacian',alpha) 近似二维拉普拉斯运算滤波器 H=fspecial('log',n,sigma) 高斯拉普拉斯(LoG)运算滤波器 H=fspecial('average',n) 均值滤波器 H=fspecial('unsharp',alpha) 模糊对比增强滤波器 说明:对于形式 H=fspecial(type) ,fspecial 函数产生一个由 type 指定的二维滤波器 H ,返回的 H 常与其它滤波器搭配使用。 4. 彩色增强的 Matlab 实现 4.1 imfilter函数 功能:真彩色增强 格式:B=imfilter(A,h) 说明:将原始图像 A 按指定的滤波器 h 进行滤波增强处理,增强后的图像 B 与 A 的尺寸和类型相同 图像的变换 1. 离散傅立叶变换的 Matlab 实现 Matlab 函数 fft、fft2 和 fftn 分别可以实现一维、二维和 N 维 DFT 算法;而函数 ifft、ifft2 和 ifftn 则用来计算反 DFT 。 这些函数的调用格式如下: A=fft(X,N,DIM) 其中,X 表示输入图像;N 表示采样间隔点,如果 X 小于该数值,那么 Matlab 将会对 X 进行零填充,否则将进行截取,使之长度为 N ;DIM 表示要进行离散傅立叶变换。 A=fft2(X,MROWS,NCOLS) 其中,MROWS 和 NCOLS 指定对 X 进行零填充后的 X 大小。 A=fftn(X,SIZE) 其中,SIZE 是一个向量,它们每一个元素都将指定 X 相应维进行零填充后的长度。 函数 ifft、ifft2 和 ifftn的调用格式于对应的离散傅立叶变换函数一致。 例子:图像的二维傅立叶频谱 % 读入原始图像 I=imread('lena.bmp'); imshow(I) % 求离散傅立叶频谱 J=fftshift(fft2(I)); figure; imshow(log(abs(J)),[8,10]) 2. 离散余弦变换的 Matlab 实现 2.1. dCT2 函数 功能:二维 DCT 变换 格式:B=dct2(A) B=dct2(A,m,n) B=dct2(A,[m,n]) 说明:B=dct2(A) 计算 A 的 DCT 变换 B ,A 与 B 的大小相同;B=dct2(A,m,n) 和 B=dct2(A,[m,n]) 通过对 A 补 0 或剪裁,使 B 的大 小为 m×n。 2.2. dict2 函数 功能:DCT 反变换 格式:B=idct2(A) B=idct2(A,m,n) B=idct2(A,[m,n]) 说明:B=idct2(A) 计算 A 的 DCT 反变换 B ,A 与 B 的大小相同;B=idct2(A,m,n) 和 B=idct2(A,[m,n]) 通过对 A 补 0 或剪裁,使 B 的大小为 m×n。 2.3. dctmtx函数 功能:计算 DCT 变换矩阵 格式:D=dctmtx(n) 说明:D=dctmtx(n) 返回一个 n×n 的 DCT 变换矩阵,输出矩阵 D 为 double 类型。 3. 图像小波变换的 Matlab 实现 3.1 一维小波变换的 Matlab 实现 (1) dwt 函数 功能:一维离散小波变换 格式:[cA,cD]=dwt(X,'wname') [cA,cD]=dwt(X,Lo_D,Hi_D) 说明:[cA,cD]=dwt(X,'wname') 使用指定的小波基函数 'wname' 对信号 X 进行分解,cA、cD 分别为近似分量和细节分量;[cA,cD]=dwt(X,Lo_D,Hi_D) 使用指定的滤波器组 Lo_D、Hi_D 对信号进行分解。 (2) idwt 函数 功能:一维离散小波反变换 格式:X=idwt(cA,cD,'wname') X=idwt(cA,cD,Lo_R,Hi_R) X=idwt(cA,cD,'wname',L) X=idwt(cA,cD,Lo_R,Hi_R,L) 说明:X=idwt(cA,cD,'wname') 由近似分量 cA 和细节分量 cD 经小波反变换重构原始信号 X 。 'wname' 为所选的小波函数 X=idwt(cA,cD,Lo_R,Hi_R) 用指定的重构滤波器 Lo_R 和 Hi_R 经小波反变换重构原始信号 X 。 X=idwt(cA,cD,'wname',L) 和 X=idwt(cA,cD,Lo_R,Hi_R,L) 指定返回信号 X 中心附近的 L 个点。 3.2 二维小波变换的 Matlab 实现 二维小波变换的函数 ------------------------------------------------- 函数名 函数功能 --------------------------------------------------- dwt2 二维离散小波变换 wavedec2 二维信号的多层小波分解 idwt2 二维离散小波反变换 waverec2 二维信号的多层小波重构 wrcoef2 由多层小波分解重构某一层的分解信号 upcoef2 由多层小波分解重构近似分量或细节分量 detcoef2 提取二维信号小波分解的细节分量 appcoef2 提取二维信号小波分解的近似分量 upwlev2 二维小波分解的单层重构 dwtpet2 二维周期小波变换 idwtper2 二维周期小波反变换 ------------------------------------------------------------- (1) wcodemat 函数 功能:对数据矩阵进行伪彩色编码 格式:Y=wcodemat(X,NB,OPT,ABSOL) Y=wcodemat(X,NB,OPT) Y=wcodemat(X,NB) Y=wcodemat(X) 说明:Y=wcodemat(X,NB,OPT,ABSOL) 返回数据矩阵 X 的编码矩阵 Y ;NB 伪编码的最大值,即编码范围为 0~NB,缺省值 NB=16; OPT 指定了编码的方式(缺省值为 'mat'),即: OPT='row' ,按行编码 OPT='col' ,按列编码 OPT='mat' ,按整个矩阵编码 ABSOL 是函数的控制参数(缺省值为 '1'),即: ABSOL=0 时,返回编码矩阵 ABSOL=1 时,返回数据矩阵的绝对值 ABS(X) (2) dwt2 函数 功能:二维离散小波变换 格式:[cA,cH,cV,cD]=dwt2(X,'wname') [cA,cH,cV,cD]=dwt2(X,Lo_D,Hi_D) 说明:[cA,cH,cV,cD]=dwt2(X,'wname')使用指定的小波基函数 'wname' 对二维信号 X 进行二维离散小波变幻;cA,cH,cV,cD 分别为近似分 量、水平细节分量、垂直细节分量和对角细节分量;[cA,cH,cV,cD]=dwt2(X,Lo_D,Hi_D) 使用指定的分解低通和高通滤波器 Lo_D 和 Hi_D 分 解信号 X 。 (3) wavedec2 函数 功能:二维信号的多层小波分解 格式:[C,S]=wavedec2(X,N,'wname') [C,S]=wavedec2(X,N,Lo_D,Hi_D) 说明:[C,S]=wavedec2(X,N,'wname') 使用小波基函数 'wname' 对二维信号 X 进行 N 层分解;[C,S]=wavedec2(X,N,Lo_D,Hi_D) 使用指定 的分解低通和高通滤波器 Lo_D 和 Hi_D 分解信号 X 。 (4) idwt2 函数 功能:二维离散小波反变换 格式:X=idwt2(cA,cH,cV,cD,'wname') X=idwt2(cA,cH,cV,cD,Lo_R,Hi_R) X=idwt2(cA,cH,cV,cD,'wname',S) X=idwt2(cA,cH,cV,cD,Lo_R,Hi_R,S) 说明:X=idwt2(cA,cH,cV,cD,'wname') 由信号小波分解的近似信号 cA 和细节信号 cH、cH、cV、cD 经小波反变换重构原信号 X ;X=idwt2(cA,cH,cV,cD,Lo_R,Hi_R) 使用指定的重构低通和高通滤波器 Lo_R 和 Hi_R 重构原信号 X ;X=idwt2(cA,cH,cV,cD,'wname',S) 和 X=idwt2(cA,cH,cV,cD,Lo_R,Hi_R,S) 返回中心附近的 S 个数据点。 (5) waverec2 函数 说明:二维信号的多层小波重构 格式:X=waverec2(C,S,'wname') X=waverec2(C,S,Lo_R,Hi_R) 说明:X=waverec2(C,S,'wname') 由多层二维小波分解的结果 C、S 重构原始信号 X ,'wname' 为使用的小波基函数;X=waverec2(C,S,Lo_R,Hi_R) 使用重构低通和高通滤波器 Lo_R 和 Hi_R 重构原信号。 图像处理工具箱 1. 图像图像数据 缺省情况下,MATLAB将图像中的数据存储为双精度类型(double),64位浮点 数,所需存储量很大;MATLAB还支持另一种类型无符号整型(uint8),即图像矩 阵中每个数据占用1个字节。 在使用MATLAB工具箱时,一定要注意函数所要求的参数类型。另外,uint8 与double两种类型数据的值域不同,编程需注意值域转换。 从uint8到double的转换 --------------------------------------------- 图像类型 MATLAB语句 --------------------------------------------- 索引色 B=double(A)+1 索引色或真彩色 B=double(A)/255 二值图像 B=double(A) --------------------------------------------- 从double到uint8的转换 --------------------------------------------- 图像类型 MATLAB语句 --------------------------------------------- 索引色 B=uint8(round(A-1)) 索引色或真彩色 B=uint8(round(A*255)) 二值图像 B=logical(uint8(round(A))) --------------------------------------------- 2. 图像处理工具箱所支持的图像类型 2.1 真彩色图像 R、G、B三个分量表示一个像素的颜色。如果要读取图像中(100,50)处的像素值, 可查看三元数据(100,50,1:3)。 真彩色图像可用双精度存储,亮度值范围是[0,1];比较符合习惯的存储方法是用无 符号整型存储,亮度值范围[0,255] 2.2 索引色图像 包含两个结构,一个是调色板,另一个是图像数据矩阵。调色板是一个有3列和若干行 的色彩映象矩阵,矩阵每行代表一种颜色,3列分别代表红、绿、蓝色强度的双精度数。 注意:MATLAB中调色板色彩强度[0,1],0代表最暗,1代表最亮。 常用颜色的RGB值 -------------------------------------------- 颜色 R G B 颜色 R G B -------------------------------------------- 黑 0 0 1 洋红 1 0 1 白 1 1 1 青蓝 0 1 1 红 1 0 0 天蓝 0.67 0 1 绿 0 1 0 橘黄 1 0.5 0 蓝 0 0 1 深红 0.5 0 0 黄 1 1 0 灰 0.5 0.5 0.5 -------------------------------------------- 产生标准调色板的函数 ------------------------------------------------- 函数名 调色板 ------------------------------------------------- Hsv 色彩饱和度,以红色开始,并以红色结束 Hot 黑色-红色-黄色-白色 Cool 青蓝和洋红的色度 Pink 粉红的色度 Gray 线型灰度 Bone 带蓝色的灰度 Jet Hsv的一种变形,以蓝色开始,以蓝色结束 Copper 线型铜色度 Prim 三棱镜,交替为红、橘黄、黄、绿和天蓝 Flag 交替为红、白、蓝和黑 -------------------------------------------------- 缺省情况下,调用上述函数灰产生一个64×3的调色板,用户也可指定调色板大小。 索引色图像数据也有double和uint8两种类型。 当图像数据为double类型时,值1代表调色板中的第1行,值2代表第2行…… 如果图像数据为uint8类型,0代表调色板的第一行,,值1代表第2行…… 2.3 灰度图像 存储灰度图像只需要一个数据矩阵。 数据类型可以是double,[0,1];也可以是uint8,[0,255] 2.4 二值图像 二值图像只需一个数据矩阵,每个像素只有两个灰度值,可以采用uint8或double类型存储。 MATLAB工具箱中以二值图像作为返回结果的函数都使用uint8类型。 2.5 图像序列 MATLAB工具箱支持将多帧图像连接成图像序列。 图像序列是一个4维数组,图像帧的序号在图像的长、宽、颜色深度之后构成第4维。 分散的图像也可以合并成图像序列,前提是各图像尺寸必须相同,若是索引色图像, 调色板也必须相同。 可参考cat()函数 A=cat(4,A1,A2,A3,A4,A5) 3. MATLAB图像类型转换 图像类型转换函数 --------------------------------------------------------------------------- 函数名 函数功能 --------------------------------------------------------------------------- dither 图像抖动,将灰度图变成二值图,或将真彩色图像抖动成索引色图像 gray2ind 将灰度图像转换成索引图像 grayslice 通过设定阈值将灰度图像转换成索引色图像 im2bw 通过设定亮度阈值将真彩色、索引色、灰度图转换成二值图 ind2gray 将索引色图像转换成灰度图像 ind2rgb 将索引色图像转换成真彩色图像 mat2gray 将一个数据矩阵转换成一副灰度图 rgb2gray 将一副真彩色图像转换成灰度图像 rgb2ind 将真彩色图像转换成索引色图像 ---------------------------------------------------------------------------- 4. 图像文件的读写和查询 4.1 图形图像文件的读取 利用函数imread()可完成图形图像文件的读取,语法: A=imread(filename,fmt) [X,map]=imread(filename,fmt) [...]=imread(filename) [...]=imread(filename,idx) (只对TIF格式的文件) [...]=imread(filename,ref) (只对HDF格式的文件) 通常,读取的大多数图像均为8bit,当这些图像加载到内存中时,Matlab就将其存放 在类uint8中。此为Matlab还支持16bit的PNG和TIF图像,当读取这类文件时,Matlab就将 其存贮在uint16中。 注意:对于索引图像,即使图像阵列的本身为类uint8或类uint16,imread函数仍将 颜色映象表读取并存贮到一个双精度的浮点类型的阵列中。 4.2 图形图像文件的写入 使用imwrite函数,语法如下: imwrite(A,filename,fmt) imwrite(X,map,filename,fmt) imwrite(...,filename) imwrite(...,parameter,value) 当利用imwrite函数保存图像时,Matlab缺省的方式是将其简化道uint8的数据格式。 4.3 图形图像文件信息的查询 imfinfo()函数 5. 图像文件的显示 5.1 索引图像及其显示 方法一: image(X) colormap(map) 方法二: imshow(X,map) 5.2 灰度图像及其显示 Matlab 7.0 中,要显示一副灰度图像,可以调用函数 imshow 或 imagesc (即 imagescale,图像缩放函数) (1) imshow 函数显示灰度图像 使用 imshow(I) 或 使用明确指定的灰度级书目:imshow(I,32) 由于Matlab自动对灰度图像进行标度以适合调色板的范围,因而可以使用自定义 大小的调色板。其调用格式如下: imshow(I,[low,high]) 其中,low 和 high 分别为数据数组的最小值和最大值。 (2) imagesc 函数显示灰度图像 下面的代码是具有两个输入参数的 imagesc 函数显示一副灰度图像 imagesc(1,[0,1]); colormap(gray); imagesc 函数中的第二个参数确定灰度范围。灰度范围中的第一个值(通常是0), 对应于颜色映象表中的第一个值(颜色),第二个值(通常是1)则对应与颜色映象表 中的最后一个值(颜色)。灰度范围中间的值则线型对应与颜色映象表中剩余的值(颜色)。 在调用 imagesc 函数时,若只使用一个参数,可以用任意灰度范围显示图像。在该 调用方式下,数据矩阵中的最小值对应于颜色映象表中的第一个颜色值,数据矩阵中的最大 值对应于颜色映象表中的最后一个颜色值。 5.3 RGB 图像及其显示 (1) image(RGB) 不管RGB图像的类型是double浮点型,还是 uint8 或 uint16 无符号整数型,Matlab都 能通过 image 函数将其正确显示出来。 RGB8 = uint8(round(RGB64×255)); % 将 double 浮点型转换为 uint8 无符号整型 RGB64 = double(RGB8)/255; % 将 uint8 无符号整型转换为 double 浮点型 RGB16 = uint16(round(RGB64×65535)); % 将 double 浮点型转换为 uint16 无符号整型 RGB64 = double(RGB16)/65535; % 将 uint16 无符号整型转换为 double 浮点型 (2) imshow(RGB) 参数是一个 m×n×3 的数组 5.4 二进制图像及其显示 (1) imshow(BW) 在 Matlab 7.0 中,二进制图像是一个逻辑类,仅包括 0 和 1 两个数值。像素 0 显示 为黑色,像素 1 显示为白色。 显示时,也可通过NOT(~)命令,对二进制图象进行取反,使数值 0 显示为白色;1 显示 为黑色。 例如: imshow(~BW) (2) 此外,还可以使用一个调色板显示一副二进制图像。如果图形是 uint8 数据类型, 则数值 0 显示为调色板的第一个颜色,数值 1 显示为第二个颜色。 例如: imshow(BW,[1 0 0;0 0 1]) 5.5 直接从磁盘显示图像 可使用一下命令直接进行图像文件的显示: imshow filename 其中,filename 为要显示的图像文件的文件名。 如果图像是多帧的,那么 imshow 将仅显示第一帧。但需注意,在使用这种方式时,图像 数据没有保存在Matlab 7.0 工作平台。如果希望将图像装入工作台中,需使用 getimage 函 数,从当前的句柄图形图像对象中获取图像数据, 命令形式为: rgb = getimage; bwlabel 功能: 标注二进制图像中已连接的部分。 L = bwlabel(BW,n) [L,num] = bwlabel(BW,n) isbw 功能: 判断是否为二进制图像。 语法: flag = isbw(A) 相关命令: isind, isgray, isrgb 74.isgray 功能: 判断是否为灰度图像。 语法: flag = isgray(A) 相关命令: isbw, isind, isrgb 11.bwselect 功能: 在二进制图像中选择对象。 语法: BW2 = bwselect(BW1,c,r,n) BW2 = bwselect(BW1,n) [BW2,idx] = bwselect(...) 举例 BW1 = imread('text.tif'); c = [16 90 144]; r = [85 197 247]; BW2 = bwselect(BW1,c,r,4); imshow(BW1) figure, imshow(BW2) 47.im2bw 功能: 转换图像为二进制图像。 语法: BW = im2bw(I,level) BW = im2bw(X,map,level) BW = im2bw(RGB,level) 举例 load trees BW = im2bw(X,map,0.4); imshow(X,map)
在Python中,可以使用颜色空间转换库`colorsys`来进行HSL(色相、饱和度、亮度)调节色域。`colorsys`库提供了一些函数来在RGB和HSL之间进行转换。 要调节HSL色域,首先需要将RGB颜色转换为HSL颜色空间,然后对HSL值进行调节,最后再将HSL颜色转换回RGB颜色。 下面是一个简单的示例代码,演示了如何使用`colorsys`库来调节HSL色域: ```python import colorsys def adjust_hsl(rgb_color, h_adjust=0, s_adjust=0, l_adjust=0): # 将RGB颜色转换为HSL颜色 hsl_color = colorsys.rgb_to_hls(*rgb_color) # 调整HSL值 hsl_color_adjusted = ( hsl_color[0] + h_adjust, # 色相调整 max(0, min(1, hsl_color[1] + s_adjust)), # 饱和度调整 max(0, min(1, hsl_color[2] + l_adjust)) # 亮度调整 ) # 将HSL颜色转换回RGB颜色 rgb_color_adjusted = colorsys.hls_to_rgb(*hsl_color_adjusted) return tuple(int(c * 255) for c in rgb_color_adjusted) # 示例调用 rgb_color = (255, 0, 0) # 红色 h_adjust = 0.2 # 色相调整值 s_adjust = -0.1 # 饱和度调整值 l_adjust = 0.1 # 亮度调整值 adjusted_color = adjust_hsl(rgb_color, h_adjust, s_adjust, l_adjust) print(adjusted_color) ``` 在上面的示例中,`adjust_hsl`函数接受一个RGB颜色元组和三个调整值(h_adjust、s_adjust、l_adjust),并返回调整后的RGB颜色元组。调整值可以是正数或负数,用于增加或减少对应的HSL分量。 请注意,上述示例中的调整值是相对于原始颜色的调整量。如果要直接设置HSL分量的绝对值,请根据需要修改代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值