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

相关文章

来自专栏前端知识分享

第162天:canvas中Konva库的使用方法

571
来自专栏腾讯IVWEB团队的专栏

踩坑记:当 JavaScript 遇上 UINT 64

写下这篇文章的缘由是因为在项目过程中,碰到了一个使用 JavaScript 处理 UINT64 类型数字的坑。二进制浮点数中的 0.1 和 0.2 并不是十分...

6850
来自专栏CNN

RenderScript 让你的Android计算速度快的飞上天!

在上一篇文章Android自动手绘,圆你儿时画家梦! 中结尾提到,我将介绍提升轮廓提取速度相关内容,今天一起学习Android中的RenderScript。看完...

621
来自专栏Java工程师日常干货

使用Google Guava快乐编程以面向对象思想处理字符串:Joiner/Splitter/CharMatcher对基本类型进行支持对JDK集合的有效补充函数式编程:Functions断言:Pred

目前Google Guava在实际应用中非常广泛,本篇博客将以博主对Guava使用的认识以及在项目中的经验来给大家分享!正如标题所言,学习使用Google Gu...

703
来自专栏calmound

D3DXCreateTextureFromFile

HRESULT D3DXCreateTextureFromFile( __in LPDIRECT3DDEVICE9 pDevice, _...

2685
来自专栏岑玉海

Spark源码系列(九)Spark SQL初体验之解析过程详解

好久没更新博客了,之前学了一些R语言和机器学习的内容,做了一些笔记,之后也会放到博客上面来给大家共享。一个月前就打算更新Spark Sql的内容了,因为一些别的...

3025
来自专栏架构之路

HTML5 自定义属性 data-* 和 jQuery.data 详解

新的HTML5标准允许你在普通的元素标签里,嵌入类似data-*的属性,来实现一些简单数据的存取。它的数量不受限制,并且也能由javascript动态修改,也支...

2895
来自专栏用户2442861的专栏

如何给10^7个数据量的磁盘文件排序

第一节、如何给磁盘文件排序 问题描述: 输入:一个最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数)的文件,其中每个数都小于等于n,且n=...

522
来自专栏hightopo

原 基于 HTML5 Canvas 的 3

935
来自专栏HT

基于 HTML5 Canvas 的 3D 碰撞检测

这是公司大神写的一个放官网上给用户学习的例子,我一开始真的不知道这是在干嘛,就只是将三个形状图元组合在一起,然后可以同时旋转、放大缩小这个三个图形,点击“Ani...

1855

扫码关注云+社区