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 条评论
登录 后参与评论

相关文章

来自专栏点滴积累

geotrellis使用(十一)实现空间数据库栅格化以及根据属性字段进行赋值

Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html 目录 前言 安装空...

3487
来自专栏Petrichor的专栏

tensorflow: variable初始化

tf.global_variables_initializer() 将在其创建时查看全局图并自动将依赖关系添加到图中的每个 tf.initializer。

772
来自专栏君赏技术博客

HQ移动20170317期周报

删除缓存:rm ~/Library/Caches/CocoaPods/search_index.json

973
来自专栏hrscy

iOS 9 Storyboard 教程(一下)

你可以直接从storyboard编辑器中,使用原型cell你可以很容易的为你的tableViewCell设计一套自定义的布局.

1312
来自专栏老马寒门IT

jQuery EasyUI 详解

easyui 为创建现代化,互动,JavaScript 应用程序,提供必要的功能。

950
来自专栏琯琯博客

Yii2 学习笔记之 GridView DetailView

2776
来自专栏逆向技术

32位汇编第五讲,逆向实战干货,(OD)快速定位扫雷内存.

      32位第五讲,逆向实战干货,快速定位扫雷内存. 首先,在逆向之前,大家先对OD有一个认识. 一丶OD的使用 ? 标号1: 反汇编窗口 (显示代码的地...

1859
来自专栏CRPER折腾记

Vue 折腾记 - (4) 写一个不大靠谱的 loading 组件

有需求,就要动手丰衣足食...公司考虑兼容IE9,那么css3 animation写的loading就无缘了 因为keyframes IE10+ , 那么要实现...

592
来自专栏数说工作室

【SAS Says】基础篇:ODS的使用(上)

你不可能总是在SAS上查看结果,如果结果很多你要一一的讲结果复制到word中去,有ODS就好啦!它可以把SAS的结果直接输出到word、PDF等文件中。 5.1...

4056
来自专栏liulun

自己动手写UI库——引入ExtJs(布局)

第一:来看一下最终的效果 ? 第二:来看一下使用方法: ? 第三: Component类代码如下所示: public class Compo...

1745

扫码关注云+社区