jashliao 用 VC++ 實現 fanfuhan OpenCV 教學004 ~ opencv-004-圖像像素讀寫操作 [一般像素存取操作(Vec3b)/指標像素存取操作(uchar *)、手工RGB顏色分離、圖片顏色反轉]
jashliao 用 VC++ 實現 fanfuhan OpenCV 教學004 ~ opencv-004-圖像像素讀寫操作 [一般像素存取操作(Vec3b)/指標像素存取操作(uchar *)、手工RGB顏色分離、圖片顏色反轉]
資料來源: https://fanfuhan.github.io/
https://fanfuhan.github.io/2019/03/21/opencv-004/
GITHUB:https://github.com/jash-git/fanfuhan_ML_OpenCV
https://github.com/jash-git/jashliao-implements-FANFUHAN-OPENCV-with-VC
★前言:

★主題:
OPENCV支援直接存取圖像中各像素點的讀取與設定,方便使用者可以不透過內建函數功能自由實作自己的演算法。
★C++
// VC_FANFUHAN_OPENCV004.cpp : 定義主控台應用程式的進入點。
//
#include "stdafx.h"
/*
// Debug | x32
通用屬性
| C/C++
| | 一般
| | 其他 Include 目錄 -> C:\opencv\build\include
|
| 連結器
| |一一般
| | 其他程式庫目錄 -> C:\opencv\build\x64\vc15\lib
|
| |一輸入
| | 其他相依性 -> opencv_world411d.lib;%(AdditionalDependencies)
// Releas | x64
組態屬性
| C/C++
| | 一般
| | 其他 Include 目錄 -> C:\opencv\build\include
|
| 連結器
| |一般
| | 其他程式庫目錄 -> C:\opencv\build\x64\vc15\lib
|
| |一輸入
| | 其他相依性 -> opencv_world411.lib;%(AdditionalDependencies)
*/
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
void pause()
{
printf("Press Enter key to continue...");
fgetc(stdin);
}
int main()
{
Mat src = imread("../../images/l_hires.jpg");//IDE 測試路徑 , IMREAD_GRAYSCALE
//Mat src = imread("../../../images/l_hires.jpg");//執行檔 測試路徑
if (src.empty()) {
cout << "could not load image..." << endl;
pause();
return -1;
}
else
{
namedWindow("input");
imshow("input", src);
int height = src.rows;
int width = src.cols;
int ch = src.channels();
/*
Mat color_reverse = Mat::zeros(src.size(), src.type());
Mat OnlyRed = Mat::zeros(src.size(), src.type());
Mat OnlyGreen = Mat::zeros(src.size(), src.type());
Mat OnlyBlue = Mat::zeros(src.size(), src.type());
// 直接读取图像像素,將圖片顏色反轉
for (int row = 0; row < height; ++row)
{
for (int col = 0; col < width; ++col)
{
if (ch == 3) {
Vec3b bgr = src.at<Vec3b>(row, col);
Vec3b bgrreverse;
Vec3b bgrRed;
Vec3b bgrGreen;
Vec3b bgrBlue;
bgrreverse[0] = 255 - bgr[0];//依序取出藍色,並反轉
bgrreverse[1] = 255 - bgr[1];//依序取出綠色,並反轉
bgrreverse[2] = 255 - bgr[2];//依序取出紅色,並反轉
bgrRed[0] = 0;
bgrRed[1] = 0;
bgrRed[2] = bgr[2];;
bgrGreen[0] = 0;
bgrGreen[1] = bgr[1];;
bgrGreen[2] = 0;
bgrBlue[0] = bgr[0];;
bgrBlue[1] = 0;
bgrBlue[2] = 0;
color_reverse.at<Vec3b>(row, col) = bgrreverse;
OnlyRed.at<Vec3b>(row, col) = bgrRed;
OnlyGreen.at<Vec3b>(row, col) = bgrGreen;
OnlyBlue.at<Vec3b>(row, col) = bgrBlue;
}
else if (ch == 1) {
int gray = src.at<uchar>(row, col);
color_reverse.at<uchar>(row, col) = 255 - gray;
}
}
}
if (ch != 1)
{
namedWindow("OnlyRed");
imshow("OnlyRed", OnlyRed);
namedWindow("OnlyGreen");
imshow("OnlyGreen", OnlyGreen);
namedWindow("OnlyBlue");
imshow("OnlyBlue", OnlyBlue);
}
namedWindow("color_reverse");
imshow("color_reverse", color_reverse);
//*/
//*
// 指针读取
Mat result = Mat::zeros(src.size(), src.type());
Mat OnlyRed = Mat::zeros(src.size(), src.type());
Mat OnlyGreen = Mat::zeros(src.size(), src.type());
Mat OnlyBlue = Mat::zeros(src.size(), src.type());
int blue = 0, green = 0, red = 0;
int gray;
for (int row = 0; row < height; ++row) {
// curr_row为第row行的首地址,遍历时,前三个字节表示的是第一个像素的BGR值,
// 注意BGR值顺序,接下来三个字节是第二个像素的值。
uchar *curr_row = src.ptr<uchar>(row);
uchar *result_row = result.ptr<uchar>(row);
uchar *OnlyRed_row = OnlyRed.ptr<uchar>(row);
uchar *OnlyGreen_row = OnlyGreen.ptr<uchar>(row);
uchar *OnlyBlue_row = OnlyBlue.ptr<uchar>(row);
for (int col = 0; col < width; ++col) {
if (ch == 3) {
blue = *curr_row++;
green = *curr_row++;
red = *curr_row++;
*result_row++ = 255 - blue;
*result_row++ = 255 - green;
*result_row++ = 255 - red;
*OnlyRed_row++ = 0;
*OnlyRed_row++ = 0;
*OnlyRed_row++ = red;
*OnlyGreen_row++ = 0;
*OnlyGreen_row++ = green;
*OnlyGreen_row++ = 0;
*OnlyBlue_row++ = blue;
*OnlyBlue_row++ = 0;
*OnlyBlue_row++ = 0;
}
else if (ch == 1) {
gray = *curr_row++;
*result_row++ = gray;
}
}
}
if (ch != 1)
{
namedWindow("OnlyRed");
imshow("OnlyRed", OnlyRed);
namedWindow("OnlyGreen");
imshow("OnlyGreen", OnlyGreen);
namedWindow("OnlyBlue");
imshow("OnlyBlue", OnlyBlue);
}
namedWindow("result");
imshow("result", result);
//*/
waitKey(0);
}
return 0;
}
★Python
import cv2 as cv
src = cv.imread("../images/liuyifei_1.png")
cv.namedWindow("input", cv.WINDOW_AUTOSIZE)
cv.imshow("input", src)
h, w, ch = src.shape
print("h , w, ch", h, w, ch)
for row in range(h):
for col in range(w):
b, g, r = src[row, col]
b = 255 - b
g = 255 - g
r = 255 - r
src[row, col] = [b, g, r]
cv.imshow("output", src)
cv.waitKey(0)
cv.destroyAllWindows()
★結果圖:

★延伸說明/重點回顧:
OPENCV要知道彩色圖片與灰階圖片是透過Mat的成員函數channels()回傳值來進行判斷(分別/判別)。
OPENCV的彩色圖片RGB的存取/儲存順序為B、G、R。