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
根據這個公式,依次讀取每個畫素點的R,G,B值,進行計算灰度值(轉換為整型數),將灰度值賦值給新影象的相應位置,所有畫素點遍歷一遍後完成轉換。
一張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.176≈306
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'); 路徑符號為單"\"