1. 程式人生 > >RGB影象轉為灰度圖

RGB影象轉為灰度圖

最後結論:

Grey = (R*38 + G*75 + B*15)>> 7

程式碼

#include <cv.h>
#include <highgui.h>
 
using namespace cv;
int main(){
         Mat src= imread("C:\\Users\\Poplar\\Pictures\\ff.jpg");
         Mat grey(src.rows, src.cols, CV_8UC1, Scalar(0));
         for (inty = 0; y < src.rows; y++)
         {
                   uchar*cp = src.ptr<uchar>(y);
                   uchar*gp = grey.ptr<uchar>(y);
                   for(int x = 0; x < src.cols; x++){
                            *gp= (15*cp[0] + 75*cp[1] + 38*cp[2]) >> 7;
                            cp+= 3;
                            gp++;
                   }
         }
         imshow("src",src);
         imshow("grey",grey);
         waitKey(0);
         return0;
}

效果如圖


下面具體解釋

RGB彩色影象中,一種彩色由R(紅色),G(綠色),B(藍色)三原色按比例混合而成。

影象的基本單元是一個畫素,就像一個巨幅電子廣告屏上遠處看是衣服影象,走近你會看到一個一個的方格,這個方格的顏色是一種,從遠處看,覺察不到這個方格的存在。

一個畫素需要3塊表示,分別代表R,G,B,如果8為表示一個顏色,就由0-255區分不同亮度的某種原色。

一張9畫素的8位RGB影象,在計算機記憶體中的分佈大概示意如下:


實際中數都是二進位制形式的,並且未必按照R,G,B順序,比如opencv是按照B,G,R順序將三個色值儲存在3個連續的位元組裡

灰度影象是用不同飽和度的黑色來表示每個影象點,比如用8位 0-255數字表示“灰色”程度,每個畫素點只需要一個灰度值,8位即可,這樣一個3X3的灰度圖,只需要9個byte就能儲存

RGB值和灰度的轉換,實際上是人眼對於彩色的感覺到亮度感覺的轉換,這是一個心理學問題,有一個公式:

Grey = 0.299*R + 0.587*G + 0.114*B

根據這個公式,依次讀取每個畫素點的RGB值,進行計算灰度值(轉換為整型數),將灰度值賦值給新影象的相應位置,所有畫素點遍歷一遍後完成轉換。

一張500X500的影象轉換為同樣大小的灰度圖需要進行25萬次上述公式的計算。進行優化是很有必要的,這個簡單的演算法是O(n)複雜度的,應該是不能優化了(或者用並行進行優化,本文不涉及),但是Grey = 0.299*R + 0.587*G + 0.114*B有更加高效的等價形式。

ALU中,位操作快於整數加法,整數加法快於整數乘法(快多少取決於有沒有乘法電路,乘法電路的結構),整數運算又比浮點數運算快得多。

所以可以通過將浮點數運算轉化為整數運算,整數運算轉換為位操作進行優化

Grey = 0.299*R + 0.587*G + 0.114*B

可以轉化為

Grey = (299*R + 587*G + 114*B + 500) /1000

整數運算會截斷小數部分,加上500是為了四捨五入(找兩個例子便可理解),減少精度損失。

這裡的除法/ 即使是整數除法計算也是很耗時,轉換為移位操作可以優化,那麼怎麼轉換為位操作?左右移位對應於乘除2的冪,為了把除法轉為右移操作,做如下處理:

Grey = 0.299*R + 0.587*G + 0.114*B

Grey = 299*R+ 587*G + 114*B÷ 1000

Grey = 1024*299*R+ 1024*587*G + 1024*114*B÷1024*1000

Grey = 306176*R+601088*G + 116736*B÷1024*1000

Grey = 306.176*R+601.088*G + 116.736*B÷1024

Grey = 306*R+601*G + 116*B÷1024//截斷誤差

Grey = 306*R+601*G + 116*B >> 10;

誤差最大是多少?

(0.176*255+0.088*255 + 0.736*255) ÷1024 = 255÷1024=0.249,可能會導致1個灰度值的波動

有一種計算方法可以降低誤差

R 的係數  =1024*0.229= 306.176306

G的係數   =1024*0.587 + 0.176 =601.264 ≈601

B的係數   =1024*0.114 + 0.264 = 117

保留了小數部分的作用,可以得到一個誤差較小的公式:

Grey = 306*R +601*G + 117*B >> 10;

這樣得來的是10位精度的。

同樣的方法可以獲得其他精度的,比如

Grey = (R*1 + G*2 + B*1) >> 2  ( Grey = (R + G<<1 + B) >> 2 )

Grey= (R*38 + G*75 + B*15) >> 7

Grey= (R*76 + G*150 + B*30) >> 8

Grey = (R*19595 + G*38469 + B*7472) >> 16

可以看出來,7位和8位精度是一樣的,比較好用的是7位精度的公式。

實際編寫程式碼時,還要考慮影象檔案的讀取問題,不同格式的RGB點陣圖,結構不同,讀取時也不同,本文不涉及影象讀取問題,這裡以openCV提供的影象讀取方式,展示轉灰度圖的實際程式碼,見文章開頭。

 2-10位精度的公式

Grey = (R*1 + G*2 + B*1) >> 2

Grey= (R*2 + G*5 + B*1) >> 3

Grey= (R*4 + G*10 + B*2) >> 4

Grey = (R*9 + G*19 + B*4) >> 5

Grey = (R*19 + G*37 + B*8) >> 6

Grey= (R*38 + G*75 + B*15) >> 7

Grey= (R*76 + G*150 + B*30) >> 8

Grey = (R*153 + G*300 + B*59) >> 9

Grey = (R*306 + G*601 + B*117) >> 10

Grey = (R*612 + G*1202 + B*234) >> 11

Grey = (R*1224 + G*2405 + B*467) >> 12

Grey= (R*2449 + G*4809 + B*934) >> 13

Grey= (R*4898 + G*9618 + B*1868) >> 14

Grey = (R*9797 + G*19235 + B*3736) >> 15

Grey = (R*19595 + G*38469 + B*7472) >> 16

Grey = (R*39190 + G*76939 + B*14943) >> 17

Grey = (R*78381 + G*153878 + B*29885) >> 18

Grey =(R*156762 + G*307757 + B*59769) >> 19

Grey= (R*313524 + G*615514 + B*119538) >> 20

相關推薦

RGB影象轉為

最後結論: Grey = (R*38 + G*75 + B*15)>> 7 程式碼 #include <cv.h> #include <highgui.h> using namespace cv; int main(){

RGB影象轉為影象原理

RGB影象轉為灰度影象 今天在幫李娜同學看程式碼的時候,突然想到了要細究RGB影象轉換為灰度影象的原理。於是開始開始了這篇blog的故事。作為一個小白,闡述可能不是很具體全面。望指正,共同進步。 總的來說RGB影象是有3個通道,也就是一個3維的矩陣,

html 影象處理 和浮雕類PS

    html5 的canvas還有一些很酷炫的效果,接下來講的是canvas對畫素的處理,雖然略有些複雜,但實現出的效果,還是很讚的~~。    為了不讓大家失望,先強調一句:下列效果需呼叫getImageData(),而這個方法會被某些瀏覽器阻止,如

圖片轉為,並修改尺寸

# 轉為灰度圖 from PIL import Image for img in os.listdir(train_path): img_open = Image.open(train_path + img) img_L = img_open.convert(

cuda練習(一):使用cuda將rbg影象轉為影象

建立工程 使用cmake建立工程,CMakeLists.txt如下: cmake_minimum_required(VERSION 2.8) project(image_process) find_package(OpenCV REQUIRED) #會去找F

【轉】從RGB轉為色演算法

一、基礎   對於彩色轉灰度,有一個很著名的心理學公式:                      

NEON 指令集並行技術優化彩色影象【Android】

  參考原文: android平臺的neon優化策略 Neon Intrinsics各函式介紹 目前市面上主流的旗艦android手機搭載的Soc都是64位的CPU,常見的armv7指令集的公版架構如Cortex-A8,Cortex-A9,Cortex-A15,常見的

【OpenCV】C++如何使RGB影象變為影象

最近在研究如何用C++來處理影象,而不使用封裝好的OpenCV程式碼,這樣能夠更好的瞭解OpenCV的內部原理。 在網上搜了一些關於C++程式碼來實現RGB(彩色)影象轉換為 gray(灰度)的原理以及程式碼,可讀性較差,所以自己整理了一下,若需轉載,請標明出處,謝謝!

基於FPGA的RGB影象影象演算法實現

一、前言   最近學習牟新剛編著《基於FPGA的數字影象處理原理及應用》的第六章直方圖操作,由於需要將捕獲的影象轉換為灰度影象,因此在之前程式碼的基礎上加入了RGB影象轉灰度影象的演算法實現。                                                           

,3通道RGB的“”,二值影象

在OpenCV中有倆巨集: COLOR_BGR2GRAY 與 COLOR_GRAY2BGR 這倆巨集主要應用在顏色空間轉換函式cvtColor函式中: cvtColor(srcImage,dstImage, COLOR_BGR2GRAY); cvtColor(srcI

opencv將轉為彩色

使用opencv將一幅灰度圖轉為彩色圖。 使用函式:cvtColor();     Mat imgGray= imread("gray.jpg",0);     Mat imgRGB;     cvtColor(

(IR )轉成 RGB 預覽,畫面出現光斑/黃斑問題解決

一、背景 存在一個 IR 圖(紅外線 Infrared Radiation),需要在頁面上顯示出來,IR 圖片格式是 gray8,即 8 位的灰度圖。 Android 上的 Bitmap 圖片格式使用的是 ARGB_8888,所以需要把灰度圖轉 ARGB 圖,每個通道都為 8 位

opencv讀取影象畫素值讀取並儲存到txt檔案(二)

#include "stdafx.h" #include"cv.h" #include <stdlib.h> #include <stdio.h> #include <math.h> #include <fstream> #include &l

可移植畫素格式 PPM,格式 PGM,點陣格式 PBM 的介紹 -- 視訊和影象程式設計基礎之一

可移植畫素圖格式 PPM,灰度圖格式 PGM,點陣圖格式 PBM 的介紹 簡介 可移植畫素圖格式(PPM),可移植灰度圖格式(PGM)和可移植點陣圖格式(PBM)是便於跨平臺的影象格式。有時候也被統稱為 PNM 格式 檔案格式描述 這三種格式其實是一樣的描述方法,只

Opencv入門筆記(1):影象載入、顯示、儲存、轉換

影象載入、顯示、儲存函式: 1         影象載入函式:imread()   Mat imread(const string& filename, int flags=1);     const string&型別的filename為載入影象的路徑(

二進位制影象影象RGB影象、索引影象

二進位制影象也稱為二值影象,通常用一個二維陣列來描述,1位表示一個畫素,組成影象的畫素值非0即1,沒有中間值,通常0表示黑色,1表示白色。二進位制影象一般用來描述文字或者圖形,優點是佔用空間少,缺點是當表示人物或者風景影象時只能描述輪廓。 灰度影象也稱單色影象,通常也有一個

如何使用 python3 將RGB 圖片轉換為

首先,介紹第一種方法, 使用  PIL  庫,   PIL庫是一種python語言常用的一個圖形處理庫。 關於   PIL  庫的安裝本文就不介紹了。   from PIL import Image I = Image

OpenCV--影象的反色與顯示

對於單通道影象: void Invert1(){ Mat src,dest; src = imread("lena.jpg"); if(!src.data){

[數字影象處理]變換——反轉,對數變換,伽馬變換,拉伸,切割,點陣切割

[plain] view plaincopyprint? close all;  clear all;  %% -------------Contrast Stretching-----------------  f = imread('washed_out_pollen_image.tif');  

Matlab影象處理轉,繪製直方圖,直方圖均衡化

1.imread() MATLAB中影象讀取函式與OpenCV一樣是imread,可以開啟指定路徑圖片,其路徑表示方式與OpenCV中有些許不同如: srcImage=imread('E:\MatlabWorkSpace\實驗一\實驗一圖一.png'); 路徑符號為單"\"