系统环境:
win 7 + VS2008 + Opencv2.1 + Excel 2010
思路:先通过Opencv库函数读取图片存储至IplImage结构体中,接着通过OLE/COM方式实现对excel文件的写入,对多个单元格的读写操作可以通过CRange中以下两个成员函数来完成。VARIANT get_Value2(); void put_Value2(VARIANT& newValue); 其中,输入参数newValue只要输入一个二维数组,即可实现向Excel中一次写入多个单元格的值。前提是程序能够通过识别图片的大小而设置二维数组的起始点,举例来说,Excel 2010 里一共有1048576行, XFD列,X是26个字母中第24个字母,F是第6个,D是第4个,因此XFD对应的是 24*26*26+6*26+4=16384,图片的高度即Excel中的行数,将图片的宽度对26进行取商求余的操作可得到由字母表示的对应的列数。
操作过程:
1、新建C++工程
新建自己的C++工程。
2、添加Excel类库
在工程名上右键,选择Add---Class,选择MFC Class From TypeLib,如图:
![](https://img-my.csdn.net/uploads/201304/15/1366029577_3486.jpg)
然后添加如图的几个类。
![](https://img-my.csdn.net/uploads/201304/15/1366029596_7259.jpg)
3. 修改头文件
进入刚添加进来的几个类头文件中将#import开头的这句注掉
// 从类型库向导中用“添加类”创建的计算机生成的 IDispatch 包装类
//#import "D:\\Program Files\\Microsoft Office\\Office14\\EXCEL.EXE" no_namespace
// CApplication 包装类
4、修改提示的错误
将修改过的工程编译一下,出现如下错误:
双击提示,在DialogBox()前加一下划线即可。
5、添加头文件
在使用导出功能的文件中添加头文件(包括opencv头文件):
#include "CApplication.h"
#include "CFont0.h"
#include "CRange.h"
#include "CWorkbook.h"
#include "CWorkbooks.h"
#include "CWorksheet.h"
#include "CWorksheets.h"
#include "afxdisp.h"
#include "comutil.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <stdlib.h>
6、使用Excel类库提供的函数将需要导出的数据导出为.xlsx文件
经过以上几步,现在可以使用Excel类库提供的函数导出数据了。与网上许多文章相对比一下,导出流程一样。只不过类库函数有所改变。函数名由Get改为get_,Set改为put_,代码如下。
说明:
1.pimg的类型 是 IplImage*,opencv库函数读取进来的图片存储在结构体 IplImage中。
2.由于初始的应用是想读出灰度图的像素值,故只输出了一个通道的值,其余两个通道可以照推。
3.如果读取的图片宽度大于256,则输出的excel文件若使用wps打开只能看到最大列为256,excel2007以上可以看到全部数值。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
void CSpectrumProDoc::OnExportexcel()
{ // TODO: 在此添加命令处理程序代码 CString sPath = _T( "D:\\Image\\"); //注意不能是c盘的路径,没有权限写入 CTime time = CTime::GetCurrentTime(); CString sfilename ; sfilename.Format( "E%02d%02d%02d%02d%02d", time.GetMonth(), time.GetDay(), time.GetHour(), time.GetMinute(), time.GetSecond()); /* 生成的文件若使用wps打开则只能看到最大列为256 */ CString strFile = sPath + sfilename + _T( ".xlsx"); CApplication app; CWorkbook book; CWorkbooks books; CWorksheet sheet; CWorksheets sheets; CRange range; CFont0 font; CRange cols; LPDISPATCH lpDisp = NULL; COleVariant covTrue(( short)TRUE); COleVariant covFalse(( short)TRUE); COleVariant covOptional(( long)DISP_E_PARAMNOTFOUND, VT_ERROR); if (!app.CreateDispatch( "Excel.Application")) { AfxMessageBox( "未能创建Excel应用程序!"); return ; } books = app.get_Workbooks(); book = books.Add(covOptional); sheets = book.get_Worksheets(); sheet = sheets.get_Item(COleVariant(( short) 1)); // range = sheet.get_Range(COleVariant("A1"), COleVariant("A1")); // range.put_Value2(COleVariant("hello excel!")); //************************************************************ CString height; if (pimg->height > 1000) { char buf1[ 5] = { 0}; //注意末尾需要以'\0'结尾 height = itoa(pimg->height, buf1, 10); } else { char buf1[ 4] = { 0}; height = itoa(pimg->height, buf1, 10); } char buf2[ 4] = { 0}; //注意末尾需要以'\0'结尾 buf2[ 0] = pimg->width / ( 26 * 26) + 64; CString dest; if (buf2[ 0] == 64) { buf2[ 1] = pimg->width / 26 + 64; buf2[ 2] = pimg->width % 26 + 64; char buf3[ 3] = {buf2[ 1], buf2[ 2], buf2[ 3]}; CString temp; temp.Format( "%s", buf3); dest = temp + height; } else { buf2[ 1] = (pimg->width - (buf2[ 0] - 64) * 26 * 26) / 26 + 64; buf2[ 2] = (pimg->width - (buf2[ 0] - 64) * 26 * 26) % 26 + 64; CString temp; temp.Format( "%s", buf2); dest = temp + height; } /*向Sheet中写入多个单元格,规模由读取的图片决定 */ lpDisp = sheet.get_Range(_variant_t( "A1"), _variant_t(dest)); range.AttachDispatch(lpDisp); VARTYPE vt = VT_I4; /*数组元素的类型,long */ SAFEARRAYBOUND sabWrite[ 2]; /*用于定义数组的维数和下标的起始值*/ sabWrite[ 0].cElements = pimg->width; sabWrite[ 0].lLbound = 0; sabWrite[ 1].cElements = pimg->height; sabWrite[ 1].lLbound = 0; COleSafeArray olesaWrite; olesaWrite.Create(vt, sizeof(sabWrite) / sizeof(SAFEARRAYBOUND), sabWrite); /*通过指向数组的指针来对二维数组的元素进行间接赋值*/ long (*pArray)[ 2] = NULL; olesaWrite.AccessData(( void **)&pArray); memset(pArray, 0, sabWrite[ 0].cElements * sabWrite[ 1].cElements * sizeof( long)); /*释放指向数组的指针*/ olesaWrite.UnaccessData(); pArray = NULL; /*对二维数组的元素进行逐个赋值*/ long index[ 2] = { 0, 0}; long lFirstLBound = 0; long lFirstUBound = 0; long lSecondLBound = 0; long lSecondUBound = 0; olesaWrite.GetLBound( 1, &lFirstLBound); olesaWrite.GetUBound( 1, &lFirstUBound); olesaWrite.GetLBound( 2, &lSecondLBound); olesaWrite.GetUBound( 2, &lSecondUBound); for ( long i = lFirstLBound; i <= lFirstUBound; i++) { index[ 0] = i; for ( long j = lSecondLBound; j <= lSecondUBound; j++) { index[ 1] = j; /* 经测试,24位深图片为8bit 3通道,灰度图(RGB都相等) */ /* 如果是8bit 1通道的图像 I(x,y) ~ ((uchar*)(img->imageData + img->widthStep*y))[x] */ long lElement = ((uchar *)(pimg->imageData + pimg->widthStep * j))[i * 3]; olesaWrite.PutElement(index, &lElement); } } /*把ColesaWritefeArray变量转换为VARIANT,并写入到Excel表格中*/ VARIANT varWrite = (VARIANT)olesaWrite; range.put_Value2(varWrite); //******************************************************************* font = range.get_Font(); font.put_Bold(COleVariant(( short)TRUE)); cols = range.get_EntireColumn(); cols.AutoFit(); app.put_Visible(TRUE); app.put_UserControl(TRUE); book.SaveCopyAs(COleVariant(strFile)); /* book.SaveAs(_variant_t(strFile), _variant_t((long)51), vtMissing, vtMissing, vtMissing, vtMissing, 0, vtMissing, vtMissing, vtMissing, vtMissing, vtMissing); */ book.put_Saved(TRUE); book.ReleaseDispatch(); books.ReleaseDispatch(); app.Quit(); app.ReleaseDispatch(); AfxMessageBox( "输出图像像素数据至excel文件成功"); } |
输出的文件如图:
参考:http://hfp0601.blog.163.com/blog/static/228483522011031104718762/
http://www.cnblogs.com/xianyunhe/archive/2011/09/25/2190485.html