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

相关文章

来自专栏落花落雨不落叶

canvas画简单电路图

85511
来自专栏ASP.NETCore

ASP.NET Core 整合Autofac和Castle实现自动AOP拦截

除了ASP.NETCore自带的IOC容器外,我们还可以使用其他成熟的DI框架,如Autofac,StructureMap等(笔者只用过Unity,Ninjec...

754
来自专栏java 成神之路

使用 NIO 实现 echo 服务器

5607
来自专栏C#

DotNet加密方式解析--非对称加密

    新年新气象,也希望新年可以挣大钱。不管今年年底会不会跟去年一样,满怀抱负却又壮志未酬。(不过没事,我已为各位卜上一卦,卦象显示各位都能挣钱...)...

5988
来自专栏张善友的专栏

LINQ via C# 系列文章

LINQ via C# Recently I am giving a series of talk on LINQ. the name “LINQ via C...

3015
来自专栏杨龙飞前端

scrollto 到指定位置

2964
来自专栏张善友的专栏

Miguel de Icaza 细说 Mix 07大会上的Silverlight和DLR

Mono之父Miguel de Icaza 详细报道微软Mix 07大会上的Silverlight和DLR ,上面还谈到了Mono and Silverligh...

3007
来自专栏陈仁松博客

ASP.NET Core 'Microsoft.Win32.Registry' 错误修复

今天在发布Asp.net Core应用到Azure的时候出现错误InvalidOperationException: Cannot find compilati...

5238
来自专栏我和未来有约会

Kit 3D 更新

Kit3D is a 3D graphics engine written for Microsoft Silverlight. Kit3D was inita...

2936
来自专栏张善友的专栏

Mix 10 上的asp.net mvc 2的相关Session

Beyond File | New Company: From Cheesy Sample to Social Platform Scott Hansel...

2787

扫码关注云+社区