如何用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 網路編程需要學習哪些網路相關的知識?

TAG:編程 | 圖像處理 | C編程語言 | 計算機圖形學 |