VS2008 + Opencv2.1 读取图片像素输出至Excel文件

系统环境:

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,如图:

然后添加如图的几个类。

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以上可以看到全部数值。

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏difcareer的技术笔记

关于EGL与示例代码[转]

OpenGL ES的javax.microedition.khronos.opengles 包定义了平台无关的GL绘图指令,EGL(javax.microedi...

863
来自专栏互联网杂技

node中Express的use深入理解

Express的API 现在学node,不来点Express,都不好意思给人打招呼。但是,我刚接触的时候,觉得好多API,感觉乱糟糟的,没办法,大脑容量不够。不...

3074
来自专栏淡定的博客

前端开发中使用mockjs模拟数据

名称:模拟的数据的名字。 值:模拟的数据的值。 规则:模拟出数据的规则,常用的几个规则:

1.6K0
来自专栏君赏技术博客

Jekyll-Admin-Mac-列表

接下来我们需要就是做出这个列表数据,我们可以使用 NSTableView来做出这个效果。

1621
来自专栏程序员的SOD蜜

使用Ring Buffer构建高性能的文件写入程序

最近常收到SOD框架的朋友报告的SOD的SQL日志功能报错:文件句柄丢失。经过分析得知,这些朋友使用SOD框架开发了访问量比较大的系统,由于忘记关闭SQL日志功...

4716
来自专栏Django中文社区

Django模板标签regroup的妙用

在使用 Django 开发时,有时候我们需要在模板中按对象的某个属性分组显示一系列数据。例如博客文章按照时间归档分组显示文章列表(示例效果请看我的博客的归档页面...

3316
来自专栏aCloudDeveloper

数据对齐详解

Author:bakari           Date:2012.8.26 数据对齐实际上是内存字节的对齐,今天偶然翻开自己以前做的笔记,发现做了好多的题,但...

23710
来自专栏游戏杂谈

使用vbscript替换excel文件的内容

这个不能算瞎折腾,也算是被逼的没办法了。从接手webgame开始,看到那么多的excel文件被翻译为繁体,我的头就没小过。现在因为新版本的问题又得重新翻译一次...

2262
来自专栏大内老A

Model验证系统运行机制是如何实现的?

在前面三篇文章(《ModelValidator》、《ModelValidatorProvider》和《ModelValidatorProviders》)中我们详...

19410
来自专栏不止是前端

Vue驱动原理

面试的时候问起vue的原理,大部分的人都会说通过Object.defineProperty修改属性的get, set方法,从而达到数据改变的目的。然而作为vue...

2175

扫码关注云+社区

领取腾讯云代金券