文章目錄
- 0.前言
- 1.提取出圖片的像素
- 2.圖片的亮度和對比度的調節
- 1.亮度和對比度和像素值之間的關系
- 2.代碼實作
- 3.其他的操作
- 1.圖片反相
- 3.圖片混合
0.前言
opencv對像素的操作有兩種,一種是對單個單個的像素進行操作(點操作),一種是對一片區域的像素進行操作,
他們可以分別用于實作不同的效果
最近主要學了一部分的點操作和一些通過點操作能實作的效果
首先便是要能取出一個圖片的所有的像素值
1.提取出圖片的像素
圖片在openCV中的操作都是通過Mat型別實作的,Mat本質上就是一個矩陣,影像的每一個像素值就是矩陣中的某一個值,
首先看一下得到單通道圖(灰度圖)的一個像素的實作
int num = img.at<uchar>(i,j);
表示將img這個灰度圖的第i列,第j行的像素值
還有三通道圖(最常見的RGB圖)的獲得一個點的像素的實作:
int b = img.at<Vec3b>(i,j)[0];
int g = img.at<Vec3b>(i,j)[1];
int r = img.at<Vec3b>(i,j)[2];
也可以獲得他的像素的floalt值
Mat m1;
imgin.convertTo(m1, CV_32F);//首先對img進行型別轉換
float b = m1.at<Vec3f>(i, j)[0];
float g = m1.at<Vec3f>(i, j)[1];
float r = m1.at<Vec3f>(i, j)[2];
也就是說,想要提取一個圖片的像素值,首先Mat變數內部的通道數和對應的資料型別,搞錯了就會報錯,然后就是你需要提取的某一點所在的行數和列數,
然后可以我們就可以對圖片進行一些操作了
2.圖片的亮度和對比度的調節
1.亮度和對比度和像素值之間的關系
參考鏈接:影像RGB值、灰度值、像素值的關系 (360doc.com)
我們可以先從灰度圖開始說一說,
亮度我感覺就是說一個影像中相對的含有白色顏色部分的多少,其中灰度圖中這種感覺尤為明顯,當整個影像對于原圖偏白時,我們就會覺得這個圖片的亮度升高了,當整個圖片對于原圖偏黑(灰)時,就會覺得這個圖片的亮度下降了,
而灰度圖的像素值就是代表圖中某一點的灰度值,像素值為255時,顯白色,像素為0時,顯黑色,
所以想要調節灰度圖的亮度時,就可以去整體改變像素的大小(讓所有的像素都去加或者減某一個值),
對比度那又是啥呢?百科的解釋:對比度指的是一幅影像中明暗區域最亮的白和最暗的黑之間不同亮度層級的測量,差異范圍越大代表對比越大,差異范圍越小代表對比越小,好的對比率120:1就可容易地顯示生動、豐富的色彩,當對比率高達300:1時,便可支持各階的顏色,
個人感覺就是大概就是黑的地方更黑,白的地方更白,而乘除的效果可以讓更高的像素值變得更高,相對較低的像素值的變化就沒那么明顯,
雖然當時我覺得對像素進行掩碼操作時對比度的增加的效果個人認為比直接將像素值乘以或者除以某一個值的效果更好,
所以對于圖片的亮度和對比度的操作的公式:
g
(
x
)
=
α
?
f
(
x
)
+
β
g(x) = \alpha * f(x) + \beta
g(x)=α?f(x)+β
α : 對 比 度 系 數 , β : 亮 度 系 數 \alpha:對比度系數 , \beta:亮度系數 α:對比度系數,β:亮度系數
三通道RGB圖片,R,G,B每一個的有效取值范圍也是在0~255,所以其實也是可以用上述這套公式的,本質是沒有變的,
有一部分沒有理解的就是,為什么直接加或者乘以某個特定的值,并且將范圍框定在0~255內,圖片仍能看出時原來的圖,色調不變,但是有一些其他的操作就會變得很奇怪
2.代碼實作
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
using namespace cv;
using namespace std;
//亮度和對比度的函式操作
Mat Image_manipulation(Mat imgin,float alpha,float beta)//alpha 對比度系數,beta 亮度系數
{
int height = imgin.rows;//行數
int width = imgin.cols;//列數
int dth = imgin.channels();//通道數
//建立空影像
Mat imgout;
imgout = Mat::zeros(imgin.size(),imgin.type());
//轉換成可以用Vec3f的資料型別
Mat m1;
imgin.convertTo(m1, CV_32F);
//進行點操作
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (dth == 3)
{
//進行操作的時候要注意資料型別
float b = m1.at<Vec3f>(i, j)[0];
float g = m1.at<Vec3f>(i, j)[1];
float r = m1.at<Vec3f>(i, j)[2];
imgout.at<Vec3b>(i, j)[0] = saturate_cast<uchar>(b * alpha + beta);//確保值的范圍在0~255
imgout.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(g * alpha + beta);
imgout.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(r * alpha + beta);
}
else if (dth == 1)
{
float gray_num = imgin.at<uchar>(i, j);
imgout.at<uchar>(i, j) = saturate_cast<uchar>(gray_num * alpha + beta);
}
}
}
return imgout;
}
int main(int argc, char** argv)
{
string path = "XXXXXX/XXXXXXX.jpg";
Mat img = imread(path);
Mat img_gray;
cvtColor(img, img_gray, CV_RGB2GRAY);
//亮度和對比度的操作
img = Image_manipulation(img, 2, 0);
img_gray = Image_manipulation(img_gray, 1.2, -50);
//imshow("img", img);
imshow("img_gray", img_gray);
waitKey(0);
return 0;
}
一些需要注意的函式
imgin.convertTo(m1, CV_32F);//轉換Mat型別
saturate_cast<uchar>(b * alpha + beta);//確保值的范圍在0~255
3.其他的操作
1.圖片反相
這個我覺得就很簡單的理解,就是用255減去像素的每一個值
其中發現直接負號像素值也能達到類似的效果
代碼(僅實作部分)
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (dth == 3)
{
//進行操作的時候要注意資料型別
int b = m1.at<Vec3b>(i, j)[0];
int g = m1.at<Vec3b>(i, j)[1];
int r = m1.at<Vec3b>(i, j)[2];
imgout.at<Vec3b>(i, j)[0] = 255-b;//確保值的范圍在0~255
imgout.at<Vec3b>(i, j)[1] = 255-g;
imgout.at<Vec3b>(i, j)[2] = 255-r;
}
else if (dth == 1)
{
int gray_num = imgin.at<uchar>(i, j);
imgout.at<uchar>(i, j) = -gray_num;
}
}
}
3.圖片混合
就是將兩個圖片分別以不同的權重加了起來,實作了兩個圖片在一起的效果
y
=
α
?
f
(
x
)
+
(
1
?
α
)
?
g
(
x
)
+
β
y = \alpha * f(x) + (1- \alpha)*g(x)+\beta
y=α?f(x)+(1?α)?g(x)+β
這里直接也能實作,也比較簡單,就是傳兩個圖片進去套入公式得到的值直接賦值給另一個圖片就行,
openCV也提供了一個api:
float alpha = 0.5;
float beta = 0;
addWeighted(img1, alpha, img2, alpha, beta, dst);
//將img1和img2用不同的權重計算得到不同的值然后賦給dst這個Mat影像
注意:img1和img2兩的圖片的大小要一樣
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/386749.html
標籤:其他
