如何用c操作圖片?
用無理數加密,如何破解? - 況琪的回答
看了這個答案,想自己寫代碼試試看。但是我的代碼不能讀取圖片。代碼:把讀的圖片按位元組16進位輸出。
#include&
int main()
{
FILE *in,*out;
int c;
out=fopen("out.txt","w");
in=fopen("pic.jpg","r");
while( ( c=fgetc(in) )!=EOF )
{
fprintf(out,"%x ",c);
}fclose(in);
fclose(out);
return 0;
}
圖:
結果:
顯然不對-_-||
那麼要這樣才能讀圖片,並像上面那位答主一樣操作圖片?
------------------------------------------------------------------------------------
更新:我現在已經知道r和rb錯了-_-||,把重點放在如何操作上吧。
謝邀~我在原答案中是使用OpenCV 2.1來處理圖片的。我對圖片的操作也是對像素進行了操作,而不是對圖片文件的二進位直接操作的。
打開每一種不同的圖像,都需要相應的解碼程序,因為絕大部分圖像都是經過壓縮的,如果你直接修改了壓縮後的數據,基本上一定會導致圖像原有的數據結構被損壞而無法打開。所以圖像處理的操作都是在解壓之後的像素上進行的。每種圖像格式的壓縮演算法都有區別,要分別編程實現。而且常用的JPG、PNG之類圖像的壓縮演算法都比較複雜,壓縮和解壓的代碼一般在2000行以上。即使是不壓縮的BMP圖像,要想比較完整地支持各種位深、帶調色板的BMP圖像,可能也需要幾百行代碼。如果你在學校里選修數字圖像處理的課,讀取BMP圖像很可能就是你們的一次大作業,網上關於BMP文件結構的資料也比較全,你也可以找來看,然後自己寫BMP的讀取程序。
幸運的是,各種圖像的讀取演算法已經在OpenCV中由各路大牛幫我們實現了。OpenCV是一個廣受讚譽的計算機視覺庫,裡面集成了大量的圖像和機器視覺演算法,可以直接調用。當然也包括打開、顯示和保存圖像。
安裝OpenCV並配置好之後,主要用到以下幾個函數讀取和操作圖像:
- cvLoadImage函數用於打開一個圖像,並返回一個指向IplImage的指針,IplImage是OpenCV中存儲圖像的結構體。這個函數會根據文件的擴展名自動選擇調用哪種圖像解碼器。
- cvShowImage用於顯示圖像,會彈出一個窗口並顯示圖像。
- cvWaitKey用於等待按鍵,如果不寫這個函數,顯示的圖像會一閃而過。一般在ShowImage之後加WaitKey,看清楚圖像後按任意鍵,代碼繼續執行。
- cvSaveImage函數用於保存一個圖像,這個函數會根據文件的擴展名自動選擇調用哪種圖像編碼器。
然後就是循環操作每個像素的方法,IplImage里有幾個重要的元素,需要了解一下:
- width:圖像寬度(像素數)
- height:圖像高度(像素數)
- widthStep:每行像素佔用的位元組數,由於內存對齊的存在,這個數據並不一定等於寬度乘以位深。
- imageData:一個指針指向圖像數據本身。對於8位灰度圖像,每像素一位元組,對於24位彩色圖像,每像素3位元組,每像素的三個位元組顏色按照BGR的順序排列,不是RGB,切記!
最後附上一個一個程序,演示打開圖像-顯示圖像-循環每個像素反色-顯示修改後的圖像
#include "opencv/cv.h"
#include "opencv/highgui.h"
int main()
{
IplImage *img = cvLoadImage("test.jpg");
cvShowImage("test image", img);
unsigned char *pImg;
for(int i = 0; i &< img-&>height; i++)
{
pImg = (unsigned char *)img-&>imageData + i * img-&>widthStep;
for(int j = 0; j &< img-&>width; j++)
{
pImg[0] ^= 255;
pImg[1] ^= 255;
pImg[2] ^= 255;
pImg += 3;
}
}
cvShowImage("inverted", img);
cvWaitKey(0);
cvReleaseImage(img);
return 0;
}
windows有操作bmp的api
"r"改成"rb"
我來手把手教題主怎麼做吧。不過是用Linux,windows沒試過。這幾天也是初學圖像處理被這個問題困擾,但是找了很久都沒找到答案,所以就自己摸索出來了。
說一下我們要做的事情,就是把一副圖片的基本信息讀取出來,保存在一個文件中。至於題主說的如何對圖像進行處理就只是修改程序的問題了。
讀取的就是我們的大美女Lena.jpg了:
讀取完的文件內容如下:
方法1:
自己去網上找到各種圖片壓縮格式的編碼規則,然後自己解析,不過這樣工作量巨巨巨大,顯然不是我們急性子想要的方法。方法2:
使用OpenCV。
我用的是OpenCV3.0,具體的安裝和配置看這裡:http://rodrigoberriel.com/2014/10/installing-opencv-3-0-0-on-ubuntu-14-04/。
在安裝測試好之後,就開始我們的讀取圖片了,OpenCV讀圖函數是這個:
Mat imread(const String filename, int flags=IMREAD_COLOR )
flags默認是IMREAD_COLOR,即彩色圖片。
Mat是OpenCV定義的數據結構:
class CV_EXPORTS Mat
{
public:
// ... a lot of methods ...
...
/*! includes several bit-fields:
- the magic signature
- continuity flag
- depth
- number of channels
*/
int flags;
//! the array dimensionality, &>= 2
int dims;
//! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions
int rows, cols;
//! pointer to the data
uchar* data;
//! pointer to the reference counter;
// when array points to user-allocated data, the pointer is NULL
int* refcount;
// other members
...
};
注意其中的data就是你想要的圖片數據了,rows和cols定義了行列。
有了這些知識就可以愉快地敲代碼了:
我們通過讀取了lena.jpg然後把他的基本信息輸出,包括dims,rows,cols和data。代碼如下:
#include &
#include &
#include &
using namespace std;
int main(){
cv::Mat img = cv::imread("lena.jpg", cv::IMREAD_COLOR);
if (!img.data){
cout &<&< "read error" &<&< endl;
return 1;
}
cout &<&< "This is a " &<&< img.dims &<&< " dementions image" &<&< endl;
cout &<&< "and has " &<&< img.rows &<&< " rows and " &<&< img.cols &<&< " columns " &<&< endl;
cout &<&< "the data in the image is : " &<&< endl;
for (int i = 0; i &< img.rows; ++i){
for (int j = 0; j &< img.cols; ++j)
printf("%x ", img.data[i * img.rows + j]);
cout &<&< endl;
}
cout &<&< endl;
cout &<&< "print success." &<&< endl;
return 0;
}
程序寫的是輸出到終端,然後我們在文件夾裡面建立一個output.txt,編譯:
g++ prtData.cpp `pkg-config --cflags --libs opencv` -o prtData
注意這裡,因為我們安裝了OpenCV,所以要加上`pkg-config --cflags --libs opencv`才可以,不然會提示undefined reference錯誤。因為如果我們不指明opencv的路徑的話鏈接器是找不到opencv庫的。我在這裡吃了大虧花了好多時間。。。
完成後就有了prtData程序了,然後執行:
./prtData &>&> output.txt
就大功告成了!
這樣就可以獲得圖片中的數據,然後怎麼修改圖片的每一個像素其實就是把程序中的printf語句修改就OK了。圖片處理,首先,不同格式的圖片顯然不一樣,
比如要處理jpeg的圖片就要知道jpeg是怎麼存圖片的,
哪些位元組是什麼信息,哪些位元組是哪個像素,哪些位元組是如何壓縮,
都搞清楚了然後隨手寫個幾千行代碼讀取出圖片就能處理了,
------
但是這些不知道沒關係,總有人知道,而且有人寫成了簡單易用的庫,比如,
libjpeg,處理jpeg格式的圖片,
libpng,處理png,
類似的還有很多,可以學著使用,
------
但是這麼多庫沒有必要一個一個都學,一些相對完善的圖形庫,都有直接一個函數自動分析各種圖片格式並載入,然後隨便處理,
SDL,QT,以及一大堆其他的,
讀到了 0X1A 返回-1.(也就是EOF)
如何處理?
in=fopen("pic.jpg","rb");
即可。
https://github.com/nothings/stb
想要快速上手的話可以用libpng、libjpeg這樣的
jpg都有封裝好的庫,難道題主想自己解析一遍二進位文件?
推薦閱讀:
※有個程序猿女朋友怎麼保護隱私?
※資料庫設計時的一些細節的東西如何處理?
※Pythonic 是什麼意思?
※如何學習 Python GUI 編程?
※Python 網路編程需要學習哪些網路相關的知識?