专利名称:猪肉颜色分级仪的制作方法
技术领域:
本项发明猪肉颜色分级仪,属于计算机视觉和农产品质量自动分级设备领域。
背景技术:
生鲜猪肉随冷藏、摆放的时间不同其质量发生显著的变化,一个简单识别的标志性指标就是猪肉的颜色,消费者经常会根据猪肉颜色的差异来选择购买,没有一个科学的、客观的颜色等级标准来参照,同时超市出售的生鲜猪肉没有依据生鲜肉的摆放时间(颜色不同)采用不同的价格,没有真正做到“按质论价”;国外的猪肉质量都有相应的颜色等级标准,他们的猪肉颜色标准在猪肉的定价、国内零售、国际贸易方面起着巨大的作用,而我国猪肉产品至今没有自己的颜色等级标准,无法和国际接轨,参与世界的猪肉贸易竞争,在国外,利用计算机视觉技术对猪肉颜色进行分级已经得到了商品化应用,但国内这方面的技术及设备还是空白。因此迫切需要建立一系列计算机分级系统,统一猪肉颜色等级标准,以适应质量控制和市场的需要。
发明内容
技术问题 本发明针对目前我国缺乏猪肉颜色计算机分级系统,建立了一套猪肉颜色分级仪,以克服传统的猪肉颜色分级主要依靠人的视觉器官进行,容易受到人的主观意志影响,分级的结果缺乏客观性的缺陷。
技术方案 一种猪肉颜色分级仪器,包括图像采集设备和猪肉颜色分级软件,其特征在于 (1)图像获取设备包括图像采集室4、数码相机5 图像采集室4为直径为600mm的半球形耐高温材料制成,内壁涂成白色,4个50W卤素灯1等间距安装于图像采集室4的底部,图像采集室4内的载样台2面为用细砂布打磨过的黑色橡胶板,样品3置于橡胶板上,图像采集室4顶端开一直径为45mm圆孔;选用CANON-PowerShotA70数码相机5,镜头穿过于图像采集室4顶圆孔; (2)猪肉颜色分级软件 猪肉颜色计算机分级软件由图像输入控制模块、图像分割与识别模块、图像颜色特征参数提取模块、猪肉颜色等级输出模块组成 a、图像输入控制模块可以自动打开数码相机5镜头、自动拍摄样品3的彩色图像; b、图像分割与识别模块用于对输入的彩色图像进行去噪、去背景、边缘提取,最终获取猪肉图像的有效特征颜色提取区域; c、图像颜色特征参数提取模块用于对图像分割与识别模块获取的有效颜色提取区域提取图像的颜色特征参数,包括红色R、绿色G、蓝色B、色彩H、饱和度S、亮度V; d、猪肉颜色等级输出模块用于调用猪肉颜色等级模型猪肉颜色等级G=4.62+6.63*S-10.20*V,输出猪肉颜色级别。
有益效果 本发明猪肉颜色分级仪已在南京苏果等超市进行小规模试用,试用后,顾客对该系统反应良好,有了这套系统,他们真切的感受到“按质论级、按级论价”带来的实惠,同时该系统性能稳定、功能齐全、使用方便、操作简单,受到超市管理人员和设备操作人员的好评。
四
图1猪肉颜色计算机分级设备图像输入系统 ①灯泡②载样台③样品④图像采集室⑤数码相机⑥数据线⑦计算机 图2猪肉颜色计算机分级仪总体框架图 五具体实施例方式 本发明为一套猪肉颜色分级仪,由图像获取设备与猪肉颜色计算机分级软件组成。
(1)图像获取设备 a、图像采集室④由直径为600mm的半球形,内壁涂成白色,4个50W卤素灯等间距安装于图像采集室④的底部,图像采集室④内的载样台②面为用细砂布打磨过的黑色橡胶板,样品③置于橡胶板上,图像采集室④顶端开一直径为45mm圆孔。
b、选用CANNON-PowerShotA70数码相机⑤,镜头穿过于图像采集室④顶圆孔。
c、数码相机⑤与计算机⑦之间采用随数码相机⑤附带的USB2.0数据线⑥连接。
(2)猪肉颜色计算机分级软件 猪肉颜色计算机分级软件由图像输入控制模块、图像分割与识别模块、图像颜色特征参数提取模块、猪肉颜色等级输出模块组成,该软件开发语言为Visual C++6.0。
a、图像输入控制模块结合Canon Digital Camera SDK6.0.1(Canon DC-SDK6.0.1)开发完成,该模块可以自动打开数码相机⑤镜头、自动拍摄样品③的彩色图像。
b、图像分割与识别模块用于对输入的彩色图像进行去噪、去背景、边缘提取,最终获取猪肉图像的有效特征颜色提取区域。
c、图像颜色特征参数提取模块用于对图像分割与识别模块获取的有效颜色提取区域提取图像的颜色特征参数,包括红色R、绿色G、蓝色B、色彩H、饱和度S、亮度V。
d、猪肉颜色等级输出模块用于调用猪肉颜色等级模型(猪肉颜色等级G=4.62+6.63*S-10.20*V),输出猪肉颜色级别,实现了猪肉颜色的分级。
系统软件的安装对系统软硬件的要求是 ●CPU在奔腾II以上内存128MB以上 硬盘20G以上 ●Windows98或以上windows操作系统 通过以上硬件设备和软件作为核心支持,最终实现了猪肉颜色计算机智能分级。附程序原代码 一、图像输入控制模块(控制数码相机) LRESULT CRelCtrlDlg∷WindowProc(UINT message,WPARAM wParam,LPARAM 1Param) { ∥TODOAdd your specialized code here and/or call the base class<!-- SIPO <DP n="2"> --><dp n="d2"/> cdError err; BOOL fRes; CProgress CProg; char szSavePath[MAX_PATH]; cdUInt32 NumData; if(message==g_ReleaseOnMessage) { /*UI is locked so that information may not be changed.*/ err=CDLockUI(m_hSource); if(GETERRORID(err)!=cdOK) { goto camerr; } /*It sets up so that a complete message may be disregarded.*/ m_fProgramRelease=TRUE; /*A special camera ends a view finder.*/ if(m_RelControlCap&cdRELEASE_CONTROL_CAP_ABORT_VIEWFINDER) { if(m_fVFEnd) { /*A view finder is ended.*/ err=CDTermViewfinder(m_hSource); if(GETERRORID(err)!=cdOK) { goto camerr; } /*A thread is ended.*/ m_fVFEnd=FALSE; g_CpVFThread->ResumeThread(); WaitForSingleObject(g_CpVFThread->m_hThread,INFINITE); Invalidate(); UpdateWindow(); } } /*A photograph is taken.*/ NumData=0; err=CDRelease(m_hSource,FALSE,NULL,NULL,cdPROG_NO_REPORT,&NumData); if(GETERRORID(err)!=cdOK) { goto camerr; } /*The directory to save is acquired.*/<!-- SIPO <DP n="3"> --><dp n="d3"/> GetSavePath(szSavePath,MAX_PATH); /*The photoed picture is saved.*/ fRes=CProg.GetReleaseData(m_hSource,NumData,szSavePath,m_fileName); if(!fRes) { goto apierr; } else if(GETERRORID(CProg.m_LastErr)==cdOPERATION_CANCELLED) { m_fProgramRelease=FALSE; CDUnlockUI(m_hSource); returnTRUE; } else if(GETERRORID(CProg.m_LastErr)!=cdOK) { err=CProg.m LastErr; goto camerr; } /*The lock of UI is canceled.*/ err=CDUnlockUI(m_hSource); if(GETERRORID(err)!=cdOK) { goto camerr; } /*It sets up so that a complete message may be received.*/ m_fProgramRelease=FALSE; returnTRUE;}else if(message==g_ReleaseCompleteMessage){ if(m_fProgramRelease==FALSE) { /*UI is locked so that information may not be changed.*/ err=CDLockUI(m_hSource); if(GETERRORID(err)!=cdOK) { goto camerr; } /*The directory to save is acquired.*/ GetSavePath(szSavePath,MAX_PATH); NumData=(cdUInt32)wParam; /*The photoed picture is saved.*/ fRes=CProg.GetReleaseData(m_hSource,NumData,szSavePath,m_fileName); if(!fRes)<!-- SIPO <DP n="4"> --><dp n="d4"/> { goto apierr; } else if(GETERRORID(CProg.m_LastErr)==cdOPERATION_CANCELLED) { m_fProgramRelease=FALSE; CDUnlockUI(m_hSource); returnTRUE; } else if(GETERRORID(CProg.m_LastErr)!=cdOK) { err=CProg.m_LastErr; goto camerr; } /*The lock of UI is canceled.*/ err=CDUnlockUI(m_hSource); if(GETERRORID(err)!=cdOK) { goto camerr; } returnTRUE; }}else if(message==g_AbortPCEVF){ if(m_fVFEnd) { /*A view finder is ended.*/ err=CDTermViewfinder(m_hSource); if(GETERRORID(err)!=cdOK) { goto camerr; } /*A thread is ended.*/ m_fVFEnd=FALSE; g_CpVFThread->ResumeThread(); WaitForSingleObject(g_CpVFThread->m_hThread,INFINITE); Invalidate(); UpdateWindow(); } return TRUE;}<!-- SIPO <DP n="5"> --><dp n="d5"/>return CDialog∷WindowProc(message,wParam,1Param); camerr char szErrStr[256]; wsprintf(szErrStr,″ErrorCode=0x%08X″,err); MessageBox(szErrStr); CDUnlockUI(m_hSource); m_fProgramRelease=FALSE; returnFALSE;apierr MessageBox(″API Error″); CDUnlockUI(m_hSource); m_fProgramRelease=FALSE; returnFALSE;}void CRelCtrlDlg∷OnDestroy(){ CDialog∷OnDestroy(); ∥TODOAdd your specialized code here and/or call the base class cdError err; char szErrStr[256]; /*End processing of CDSDK is performed.*/ err=CDFinishSDK(); if(GETERRORID(err)!=cdOK) { wsprintf(szErrStr,″ErrorCode=0x%08X″,err); MessageBox(szErrStr); }}void CRelCtrlDlg∷SetPicQuery(){ UpdateData(); cdError err1,err2; CString CAddStr; m_CInfoString=″″; /*Quality of image,image size,and the average size of a picture file are acquired.*/ cdCompQuality Quality; cdImageSize Size; ∥ () switch(m_Camsize){ case 0 Size=cdIMAGE_SIZE_SMALL;<!-- SIPO <DP n="6"> --><dp n="d6"/> break;case 1 Size=cdIMAGE_SIZE_MEDIUM1; break;case 2 Size=cdIMAGE_SIZE_MEDIUM2; break;case 3 Size=cdIMAGE_SIZE_LARGE; break;}switch(m_CamQuery){case 0 Quality=cdCOMP_QUALITY_NORMAL; break;case 1 Quality=cdCOMP_QUALITY_FINE; break;case 2 Quality=cdCOMP_QUALITY_SUPERFINE; break;}err1=CDSetImageFormatAttribute(m_hSource,Quality,Size);m_CamMode=17;cdShootingModeShootingMode;switch(m_CamMode){case 0 ShootingMode=cdSHOOTING_MODE_AUTO; break;case 1 ShootingMode=cdSHOOTING_MODE_PROGRAM; break;case 2 ShootingMode=cdSHOOTING_MODE_TV; break;case 3 ShootingMode=cdSHOOTING_MODE_AV; break;case 4 ShootingMode=cdSHOOTING_MODE_MANUAL; break;case 5<!-- SIPO <DP n="7"> --><dp n="d7"/> ShootingMode=cdSHOOTING_MODE_A_DEP; break;case 6 ShootingMode=cdSHOOTING_MODE_M_DEP; break;case 7 ShootingMode=cdSHOOTING_MODE_BULB; break;case 8 ShootingMode=cdSHOOTING_MODE_MANUAL_2; break;case 9 ShootingMode=cdSHOOTING_MODE_FAR_SCENE; break;case 10 ShootingMode=cdSHOOTING_MODE_FAST_SHUTTER; break;case 11 ShootingMode=cdSHOOTING_MODE_SLOW_SHUTTER; break;case 12 ShootingMode=cdSHOOTING_MODE_NIGHT_SCENE; break;case 13 ShootingMode=cdSHOOTING_MODE_GRAY_SCALE; break;case 14 ShootingMode=cdSHOOTING_MODE_SEPIA; break;case 15 ShootingMode=cdSHOOTING_MODE_PORTRAIT; break;case 16 ShootingMode=cdSHOOTING_MODE_SPOT; break;case 17 ShootingMode=cdSHOOTING_MODE_MACRO; break;case 18 ShootingMode=cdSHOOTING_MODE_BW; break;case 19 ShootingMode=cdSHOOTING_MODE_PANFOCUS; break;<!-- SIPO <DP n="8"> --><dp n="d8"/> case 20 ShootingMode=cdSHOOTING_MODE_VIVID; break; case 21 ShootingMode=cdSHOOTING_MODE_NEUTRAL; break; case 22 ShootingMode=cdSHOOTING_MODE_INVALID; break; } err2=CDSetShootingMode(m_hSource,ShootingMode); if(GETERRORID(err1)==cdOK/*&& GETERRORID(err2)==cdOK*/) GetCameraInformation(); else MessageBox(″Set Error″);}void CRelCtrlDlg∷SetCamMode(){ cdError err; err=CDLockUI(m_hSource); if(GETERRORID(err)!=cdOK) { goto camerr; } err=SetReleaseState(); if(GETERRORID(err)!=cdOK) { goto camerr; } /*The lock of UI is canceled.*/ err=CDUnlockUI(m_hSource); if(GETERRORID(err)!=cdOK) { goto camerr; } return;<!-- SIPO <DP n="9"> --><dp n="d9"/>camerr. char szErrStr[256]; wsprintf(szErrStr,″ErrorCode=0x%08X″,err); MessageBox(szErrStr); CDUnlockUI(m_hSource);} 二、图像分割与识别模块(-将内存中图像转化为灰度模式)。
BOOL CJiSuan∷ChangtoGrid(){ int w=m_dib.GetDIBWidth(); int h=m_dib.GetDIBHeight(); for(int i=0;i<w;i++) for(int j=O;j<h;j++) { m_dib.SetPixel(i,j,RGB(255,255,255)); if(i==10) i=w-10; if(j==10) j=h-10; } for(i=0;i<w;i++) for(int j=0;j<h;j++) { DWORD rgb=GetPixel(i,j); int Y=m_dib.FindR(rgb)-m_dib.FindB(rgb); int y=m_dib.FindR(rgb)-m_dib.FindG(rgb); if(Y>255)Y=255; if(Y<0)Y=0; if(y>255)y=255; if(y<0)y=0; Y=Y<y?Yy; SetPixel(i,j,RGB(Y,Y,Y)); } int yuZhi=FindAllYu(); for(i=0;i<w;i++) for(int j=0;j<h;j++) {<!-- SIPO <DP n="10"> --><dp n="d10"/> if(m_dib.FindR(GetPixel(i,j))<=yuZhi) { ∥ 背景色 SetPixel(i,j,RGB(255,255,255)); } } for(i=0;i<w;i++) for(int j=0;j<h;j++) { if(GetPixel(i,j)==RGB(255,255,255)) m_dib.SetPixel(i,j,RGB(255,255,255)); } if(m_pDIBData!=NULL) delete m_pDIBData; m_pDIBData=(BYTE*)new char[m_dib.GetSize()]; memcpy(m_pDIBData,m_dib.m_pDIBData,m_dib.GetSize()); for(i=0;i<w;i++) for(int j=0;j<h;j++) { DWORD rgb=GetPixel(i,j); int Y=int(-1.368612+0.441683*m_dib.FindR(rgb)+0.390386*m_dib.FindG(rgb) +0.211932*m_dib.FindB(rgb)); if(Y>255)Y=255; if(Y<0)Y=0; SetPixel(i,j,RGB(Y,Y,Y)); } return true;} 三、图像颜色特征参数提取模块(下面是处理阈值计算的) #ifndef_CThreshold_H_#define_CThreshold_H_∥计算最佳阈值class CThreshold{<!-- SIPO <DP n="11"> --><dp n="d11"/> enum{N=256};public CThreshold(){} ~CThreshold(){} void set(int g[],int a[],int total=N); double GetThreshold();protected double GetOneThreshold(intt);∥计算一个阈值 voidGetUT(); ∥计算图象灰度平均值private int gray[N],n[N],m_total,m_ntotal; double m_ut,m_threshold;∥图象灰度平均值};#endif∥_CThreshold_H_#include″stdafx.h″#include″Threshold.h″#define SQR(x)(x)*(x)void CThreshold∷set(int g[],iht a[],int total){ m_total=total; for(int i=0;i<m_total;i++){ n[i]=a[i]; gray[i]=g[i]; } GetUT();}void CThreshold∷GetUT(){ int nTotal=0; m_ut=0.0;m_ntotal=0; for(int i=0;i<m_total;i++) nTotal+=n[i]; for(i=0;i<m_total;i++){ m_ut+=1.0*gray[i]*n[i]/nTotal; m_ntotal+=n[i]; }}double CThreshold∷GetOneThreshold(int t)<!-- SIPO <DP n="12"> --><dp n="d12"/>{ ∥计算类C1的像素灰度平均值和方差,发生概率 double u1=0.0,s1=0.0,w1=0.0; int total=0; for(int i=0;i<t;i++)total+=n[i]; for(i=0;i<t;i++){ u1+=1.0*gray[i]*n[i]/total; w1+=1.0*n[i]/m_ntotal; } for(i=0;i<t;i++)s1+=1.0*SQR(gray[i]-u1)*n[i]/total; ∥计算类C2的像素灰度平均值和方差 double u2=0.0,s2=0.0,w2=0.0; total=0; for(i=t;i<m_total;i++)total+=n[i]; for(i=t;i<m_total;i++){ u2+=1.0*gray[i]*n[i]/total; w2+=1.0*n[i]/m_ntotal; } for(i=t;i<m_total;i++)s2+=1.0*SQR(gray[i]-u2)*n[i]/total; double sw2=w1*s1+w2*s2; double sb2=w1*SQR(u1-m_ut)+w2*SQR(u2-m_ut); return sb2/sw2;}double CThreshold∷GetThreshold(){ m_threshold=0; double nSepMax=0.0;∥求分离度最大的值 for(int t=0;t<m_total;t++){ double temp=GetOneThreshold(gray[t]); if(temp>nSepMax){ nSepMax=temp; m_threshold=gray[t]; } } return m_threshold;}用递归方法去除颜色值void CJiSuan∷FillGreenColor(int x,int y){<!-- SIPO <DP n="13"> --><dp n="d13"/> if(x<0‖x>m_dib.GetDIBWidth()‖y<0‖y>m_dib.GetDIBHeight()) return; if(GetPixel(x,y)==RGB(255,0,255)) SetPixel(x,y,RGB(255,255,255)); else return; FillGreenColor(x+1,y); FillGreenColor(x-1,y); FillGreenColor(x,y-1); FillGreenColor(x,y+1);}图像位图像素操作类∥DIB.cppimplementation file∥#include″stdafx.h″#include″DIB.h″#ifdef_DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[]=_FILE_;#endif///////////////////////////////////////////////////////////////////////////////////∥CDIBCDIB∷CDIB(){ m_pBMI=NULL; m_pDIBData=NULL; m_pDIBData2=NULL;}CDIB∷~CDIB(){ if(m_pBMI!=NULL) delete m_pBMI; if(m_pDIBData!=NULL) delete m_pDIBData; if(m_pDIBData2!=NULL) delete m_pDIBData2;}<!-- SIPO <DP n="14"> --><dp n="d14"/>BOOL CDIB∷LoadFromFile(LPCTSTR lpszFileName){ CFile file; BITMAPINFO*pBMI=NULL; BYTE*pDIBData=NULL; if(!file.Open(lpszFileName,CFile∷modeRead|CFile∷typeBinary)) { AfxMessageBox(″打不开文件″); return false; } BITMAPFILEHEADER bfh; if(file.Read(&bfh,sizeof(bfh))!=sizeof(bfh)) { AfxMessageBox(″读文件出错″); return false; } if(bfh.bfType!=0x4d42) { AfxMessageBox(″不是bmp文件″); return false; } BITMAPINFOHEADER bih; if(file.Read(&bih,sizeof(bih))!=sizeof(bih)) { AfxMessageBox(″读文件出错″); return false; } if(bih.biBitCount!=24) { AfxMessageBox(″不是24位图片″); return false; } pBMI=(BITMAPINFO*)new char[sizeof(BITMAPINFOHEADER)]; if(!pBMI) { AfxMessageBox(″分配内存出错″); return false; } memcpy(pBMI,&bih,sizeof(BITMAPINFOHEADER));<!-- SIPO <DP n="15"> --><dp n="d15"/> DWORD dataBytes=bfh.bfSize-bfh.bfOffBits; m_size=dataBytes; pDIBData=(BYTE*)new char[dataBytes]; if(!pDIBData) { AfxMessageBox(″分配内存出错″); delete pBMI; return false; } if(file.ReadHuge(pDIBData,dataBytes)!=dataBytes) { AfxMessageBox(″读文件出错″); delete pBMI; delete pDIBData; return false; } file.Close(); if(m_pBMI!=NULL) delete m_pBMI; m_pBMI=pBMI; if(m_pDIBData!=NULL) delete m_pDIBData; m_pDIBData=pDIBData; return true;}void CDIB∷ShowDIB(CDC*pDC,int nLeft,int nTop,int nWidth,int nHeight){ pDC->SetStretchBltMode(COLORONCOLOR); StretchDIBits(pDC->GetSafeHdc(),nLeft,nTop,nWidth,nHeight, 0,0,GetDIBWidth(),GetDIBHeight(), m_pDIBData,m_pBMI,DIB_RGB_COLORS,SRCCOPY);}////////////////////////////////////////////////////////////////////////////∥CDIB message handlersDWORD CDIB∷GetPixel(int x,int y){<!-- SIPO <DP n="16"> --><dp n="d16"/> if(m_pDIBData==NULL) { AfxMessageBox(″没有加载图像!″); return-1; } ∥一行的字节数。 return dib_GetColor(m_pDIBData+m_nPitch*y+x+x+x);}void CDIB∷SetPixel(int x,int y,DWORD c){∥dib_SetColor((BYTE*)(),c); ∥一行的字节数。 dib_SetColor((BYTE*)(m_pDIBData+m_nPitch*y+x+x+x),c);}void CDIB∷SaveImage(LPCTSTR lpszName){ BITMAPFILEHEADER bfh; memset(&bfh,0,sizeof(BITMAPFILEHEADER)); BITMAPINFOHEADER bi; bi.biSize =sizeof(BITMAPINFOHEADER); bi.biWidth =GetDIBWidth(); bi.biHeight=GetDIBHeight(); bi.biPlanes =1; bi.biBitCount =24;∥m_dib.m_nPitch*m_dib.GetDIBHeight(); bi.biCompression =BI_RGB; bi.biSizeImage =0; bi.biXPelsPerMeter =0; bi.biYPelsPerMeter =0; bi.biClrUsed =0; bi.biClrImportant =0; if(bi.biSizeImage==0) bi.biSizeImage=((((bi.biWidth*bi.biBitCount)+31)&~31)/8) *bi.biHeight; bfh.bfType=((WORD)′B′)′M′<<8; bfh.bfSize=sizeof(BITMAPFILEHEADER) +sizeof(BITMAPINFOHEADER) +bi.biSizeImage; bfh.bfOffBits=sizeof(BITMAPFILEHEADER) +sizeof(BITMAPINFOHEADER);<!-- SIPO <DP n="17"> --><dp n="d17"/> HANDLE hFile=CreateFile(lpszName,GENERIC_WRITE,0,0, CREATE_ALWAYS,0,0); DWORD dw; WriteFile(hFile,&bfh,sizeof(BITMAPFILEHEADER),&dw,NULL); WriteFile(hFile,&bi,sizeof(BITMAPINFOHEADER),&dw,NULL); WriteFile(hFile,m_pDIBData,bi.biSizeImage,&dw,NULL); CloseHandle(hFile);}int CDIB∷FindB(DWORD rgb){ DWORD b=rgb & 0x000000ff;return int(b);}int CDIB∷FindR(DWORD rgb){ ∥查找RGB色彩 DWORD r=rgb & 0x00ff0000; r=r/(16*16*16*16); return int(r);}int CDIB∷FindG(DWORD rgb){ DWORD g=rgb & 0x0000ff00; g=g/(16*16); return int(g);}DWORD CDIB∷GetSize(){ return m_size;} 四、猪肉颜色等级输出模块(图片格式转化操作类) #include″stdafx.h″#include″Picture.h″<!-- SIPO <DP n="18"> --><dp n="d18"/> #ifdet_DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[]=_FILE_; #endif #define HIMETRIC_INCH 2540 #define ERROR_TITLE″CPicture Error″∥Error Title(Related To This Class)... ∥----------------------------------------------------------------------------- ∥DoesConstructor-Create a New CPicture Object To Hold Pictre Data ∥~~~~ ∥ ∥----------------------------------------------------------------------------- CPicture∷CPicture() ∥============================================================================= { m_IPicture=NULL; m_Height=0; m_Weight=0; m_Width=0; } ∥----------------------------------------------------------------------------- ∥DoesDestructor-Free Data And Information From The CPicture Object ∥~~~~ ∥ ∥----------------------------------------------------------------------------- CPicture∷~CPicture() ∥============================================================================= { if(m_IPicture!=NULL)FreePictureData();∥Important-Avoid Leaks... } void CPicture∷FreePictureData() ∥============================================================================= { if(m_IPicture !=NULL) { m_IPicture->Release(); m_IPicture=NULL; m_Height=0;<!-- SIPO <DP n="19"> --><dp n="d19"/> m_Weight=0; m_Width=0; } } ∥----------------------------------------------------------------------------- ∥DoesOpen a Resource And Load It Into IPicture(Interface) ∥~~~~ (.BMP.DIB.EMF.GIF.ICO.JPG.WMF) ∥ ∥NoteWhen Adding a Bitmap Resource It Would Automatically Show On″Bitmap″ ∥~~~~ This NOT Good Coz We Need To Load It From a Custom Resource″BMP″ ∥ To Add a Custom RresourceImport Resource->Open As->Custom ∥ (Both.BMP And.DIB Should Be Found Under″BMP″) ∥ ∥InPut ResourceName-As a UINT Defined(ExampleIDR_PICTURE_RESOURCE) ∥~~~~~ ResourceType-Type Name(Example″JPG″) ∥ ∥OutPutTRUE If Succeeded... ∥~~~~~~ ∥----------------------------------------------------------------------------- BOOL CPicture∷Load(UINT ResourceName,LPCSTR ResourceType) ∥============================================================================= { BOOL bResult=FALSE; HGLOBAL hGlobal=NULL; HRSRChSource=NULL; LPVOID lpVoid =NULL; int nSize =0; if(m_IPicture!=NULL)FreePictureData();∥Important-Avoid Leaks... hSource=FindResource(AfxGetResourceHandle(),MAKEINTRESOURCE(ResourceName),ResourceType); if(hSource==NULL) { HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd; MessageBoxEx(hWnd,″FindResource()Failed\t″,ERROR_TTTLE,MB_OK|MB_ICONSTOP,LANG_ENGLISH); return(FALSE); }<!-- SIPO <DP n="20"> --><dp n="d20"/> hGlobal=LoadResource(AfxGetResourceHandle(),hSource); if(hGlobal==NULL) { HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd; MessageBoxEx(hWnd,″LoadResource()Failed\t″,ERROR_TITLE,MB_OKMB_ICONSTOP,LANG_ENGLISH); return(FALSE); } lpVoid=LockResource(hGlobal); if(lpVoid==NULL) { HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd; MessageBoxEx(hWnd,″LockResource()Failed\t″,ERROR_TITLE,MB_OKMB_ICONSTOP,LANG_ENGLISH); return(FALSE); } nSize=(UINT)SizeofResource(AfxGetResourceHandle(),hSource); if(LoadPictureData((BYTE*)hGlobal,nSize))bResult=TRUE; UnlockResource(hGlobal);∥16Bit Windows Needs This FreeResource(hGlobal);∥16Bit Windows Needs This(32Bit-Automatic Release) m_Weight=nSize;∥Update Picture Size Info... if(m_IPicture!=NULL)∥Do Not Try To Read From Memory That Is Not Exist... { m_IPicture->get_Height(&m_Height); m_IPicture->get_Width(&m_Width); ∥Calculate Its Size On a″Standard″(96 DPI)Device Context m_Height=MulDiv(m_Height,96,HIMETRIC_INCH); m_Width=MulDiv(m_Width,96,HIMETRIC_INCH); } else∥Picture Data Is Not a Known Picture Type { m_Height=0; m_Width=0; bResult=FALSE; } return(bResult); }<!-- SIPO <DP n="21"> --><dp n="d21"/> ∥----------------------------------------------------------------------------- ∥DoesOpen a File And Load It Into IPicture(Intefface) ∥~~~~ (.BMP.DIB.EMF.GIF.ICO.JPG.WMF) ∥ ∥InPut sFilePathName-Path And FileName Target To Save ∥~~~~~ ∥ ∥OutPutTRUE If Succeeded... ∥~~~~~~ ∥----------------------------------------------------------------------------- BOOL CPicture∷Load(CString sFilePathName) ∥============================================================================ { BOOL bResult=FALSE; CFile PictureFile; CFileException e; int nSize=0; if(m_IPicture!=NULL)FreePictureData();∥Important-Avoid Leaks... if(PictureFile.Open(sFilePathName,CFile∷modeRead|CFile∷typeBinary,&e)) { nSize=PictureFile.GetLength(); BYTE*pBuffer=new BYTE[nSize]; if(PictureFile.Read(pBufier,nSize)>0) { if(LoadPictureData(pBufier,nSize))bResult=TRUE; } PictureFile.Close(); delete[]pBuffer; } else∥Open Failed... { TCHAR szCause[255]; e.GetErrorMessage(szCause,255,NULL); CString str=szCause; if(str.Find(″sharing″)<0) { HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd; MessageBoxEx(hWnd,szCause,ERROR_TITLE,MB_OK|MB_ICONSTOP,LANG_ENGLISH);<!-- SIPO <DP n="22"> --><dp n="d22"/> } bResult=FALSE; } m_Weight=nSize;∥Update Picture Size Info...if(m_IPicture!=NULL)∥Do Not Try To Read From Memory That Is Not Exist...{m_IPicture->get_Height(&m_Height);m_IPicture->get_Width(&m_Width);∥Calculate Its Size On a″Standard″(96 DPI)Device Contextm_Height=MulDiv(m_Height,96,HIMETRIC_INCH);m_Width=MulDiv(m_Width,96,HIMETRIC_INCH);}else∥Picture Data Is Not a Known Picture Type{m_Height=0;m_Width=0;bResult=FALSE;}return(bResult);}BOOL CPicture∷LoadPictureData(BYTE*pBuffer,int nSize)∥============================================================================={BOOL bResult=FALSE;HGLOBAL hGlobal=GlobalAlloc(GMEM_MOVEABLE,nSize);if(hGlobal==NULL){HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd;MessageBoxEx(hWnd,″Can not allocate enough memory\t″,ERROR_TITLE,MB_OK |MB_ICONSTOP,LANG_ENGLISH);return(FALSE);}void*pData=GlobalLock(hGlobal);memcpy(pData,pBuffer,nSize);GlobalUnlock(hGlobal);IStream*pStream=NULL;<!-- SIPO <DP n="23"> --><dp n="d23"/> if(CreateStreamOnHGlobal(hGlobal,TRUE,&pStream)==S_OK) { HRESULT hr; if((hr=OleLoadPicture(pStream,nSize,FALSE,IID_IPicture,(LPVOID*)&m_IPicture))==E_NOINTERFACE) { HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd; MessageBoxEx(hWnd,″IPicture interface is not supported\t″,ERROR_TITLE,MB_OK|MB_ICONSTOP,LANG_ENGLISH); return(FALSE); } else∥S_OK { pStream->Release(); pStream=NULL; bResult=TRUE; } } FreeResource(hGlobal);∥16Bit Windows Needs This(32Bit-Automatic Release) return(bResult); } BOOL CPicture∷Show(CDC*pDC,CRect DrawRect) ∥============================================================================= { if(pDC==NULL‖m_IPicture==NULL)return FALSE; long Width=0; long Height=0; m_IPicture->get_Width(&Width); m_IPicture->get_Height(&Height); HRESULT hrP=NULL; hrP=m_IPicture->Render(pDC->m_hDC, DrawRect.left,∥Left DrawRect.top, ∥Top DrawRect.right-DrawRect.left,∥Right DrawRect.bottom-DrawRect.top,∥Bottom<!-- SIPO <DP n="24"> --><dp n="d24"/> 0, Height, Width, -Height, &DrawRect); if(SUCCEEDED(hrP))return(TRUE); HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd; MessageBoxEx(hWnd,″Can not allocate enough memory\t″,ERROR_TITLE,MB_OK|MB_ICONSTOP,LANG_ENGLISH); return(FALSE); } ∥----------------------------------------------------------------------------- ∥DoesDraw The Loaded Picture Direct To The Client DC ∥~~~~ ∥ ∥NoteBigger OR Smaller Dimentions Than The Original Picture Size ∥~~~~ Will Draw The Picture Streached To Its New Given Dimentions... ∥ ∥InPut pDC-Given DC To Draw On ∥~~~~~ LeftTop-Opening Point To Start Drawing(Left,Top) ∥ WidthHeight-Dimentions Of The Picture To Draw(Width,Height) ∥ MagnifyX-Magnify Pixel Width,0=Default(No Magnify) ∥ MagnifyY-Magnify Pixel Height,0=Default(No Magnify) ∥ ∥OutPutTRUE If Succeeded... ∥~~~~~~ ∥----------------------------------------------------------------------------- BOOL CPicture∷Show(CDC*pDC,CPoint LeftTop,CPoint WidthHeight,int MagnifyX,intMagnifyY) ∥============================================================================= { if(pDC==NULL‖m_IPicture==NULL)return FALSE; long Width=0; long Height=0; m_IPicture->get_Width(&Width); m_IPicture->get_Height(&Height); if(MagnifyX==NULL)MagnifyX=0; if(MagnifyY==NULL)MagnifyY=0; MagnifyX=int(MulDiv(Width,pDC->GetDeviceCaps(LOGPIXELSX),HIMETRIC_INCH)*<!-- SIPO <DP n="25"> --><dp n="d25"/>MagnifyX); MagnifyY=int(MulDiv(Height,pDC->GetDeviceCaps(LOGPIXELSY),HIMETRIC_INCH)*Magnifyy); CRect DrawRect(LeftTop.x,LeftTop.y,MagnifyX,Magnifyy); HRESULT hrP=NULL; hrp=m_IPicture->Render(pDC->m_hDC, LeftTop.x, ∥Left LeftTop.y, ∥Top WidthHeight.x+MagnifyX,∥Width WidthHeight.y+MagnifyY,∥Height 0, Height, Width, -Height, &DrawRect); if(SUCCEEDED(hrP))return(TRUE); HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd; MessageBoxEx(hWnd,″Can not allocate enough memory\t″,ERROR_TITLE,MB_OK|MB_ICONSTOP,LANG_ENGLISH); return(FALSE); } ∥----------------------------------------------------------------------------- ∥DoesSaves The Picture That Is Stored In The IPicture Object As a Bitmap ∥~~~~ (Converts From Any Known Picture Type To a Bitmap/Icon File) ∥ ∥InPut sFilePathName-Path And FileName Target To Save ∥~~~~~ ∥ ∥OutPutTRUE If Succeeded... ∥~~~~~~ ∥----------------------------------------------------------------------------- BOOL CPicture∷SaveAsBitmap(CString sFilePathName) ∥============================================================================= { BOOL bResult=FALSE; ILockBytes*Buffer=0; IStorage *pStorage=0;<!-- SIPO <DP n="26"> --><dp n="d26"/> IStream *FileStream=0; BYTE *BufferBytes; STATSTG BytesStatistics; DWORD OutData; longOutStream; CFile BitmapFile;CFileException e; double SkipFloat=0; DWORD ByteSkip=0; _ULARGE_INTEGER RealData; CreateILockBytesOnHGlobal(NULL,TRUE,&Buffer);∥Create ILockBytes Buffer HRESULT hr=∷StgCreateDocfileOnILockBytes(Buffer, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE,0,&pStorage); hr=pStorage->CreateStream(L″PICTURE″, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE,0,0,&FileStream); m_IPicture->SaveAsFile(FileStream,TRUE,&OutStream);∥Copy Data Stream FileStream->Release(); pStorage->Release(); Buffer->Flush(); ∥m_IPicture->SaveAsFile( ∥Get Statistics For Final Size Of Byte Array Buffer->Stat(&BytesStatistics,STATFLAG_NONAME); ∥Cut UnNeeded Data Coming From SaveAsFile()(Leave Only″Pure″Picture Data) SkipFloat=(double(OutStream)/512);∥Must Be In a 512 Blocks... if(SkipFloat>DWORD(SkipFloat))ByteSkip=(DWORD)SkipFloat+1; else ByteSkip=(DWORD)SkipFloat; ByteSkip=ByteSkip*512;∥Must Be In a 512 Blocks... ∥Find Difference Between The Two Values ByteSkip=(DWORD)(BytesStatistics.cbSize.QuadPart-ByteSkip); ∥Allocate Only The″Pure″Picture Data RealData.LowPart=0; RealData.HighPart=0; RealData.QuadPart=ByteSkip; BufferBytes=(BYTE*)malloc(OutStream); if(BufferBytes==NULL) { Buffer->Release();<!-- SIPO <DP n="27"> --><dp n="d27"/> HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd; MessageBoxEx(hWnd,″Can not allocate enough memory\t″,ERROR_TITLE,MB_OK|MB_ICONSTOP,LANG_ENGLISH); } Buffer->ReadAt(RealData,BufferBytes,OutStream,&OutData); if(BitmapFile.Open(sFilePathName,CFile∷typeBinary|CFile∷modeCreate|CFile∷modeWrite,&e)) { BitmapFile.Write(BufferBytes,OutData); BitmapFile.Close(); bResult=TRUE; } else∥Write File Failed... { TCHAR szCause[255]; e.GetErrorMessage(szCause,255,NULL); HWND hWnd=AfxGetApp()->GetMainWnd()->m_hWnd; MessageBoxEx(hWnd,szCause,ERROR_TITLE,MB_OK|MB_ICONSTOP,LANG_ENGLISH); bResult=FALSE; } Buffer->Release(); free(BufferBytes); return(bResult); } BOOL CPicture∷ShowBitmapResource(CDC*pDC,const int BMPResource,CPoint LeftTop) ∥============================================================================= { if(pDC==NULL)return(FALSE); CBitmap BMP; if(BMP.LoadBitmap(BMPResource)) { ∥Get Bitmap Details BITMAP BMPInfo; BMP.GetBitmap(&BMPInfo); ∥Create An In-Memory DC Compatible With The Display DC We R Gonna Paint On CDC DCMemory; DCMemory.CreateCompatibleDC(pDC); ∥Select The Bitmap Into The In-Memory DC CBitmap*pOldBitmap=DCMemory.SelectObject(&BMP); ∥Copy Bits From The In-Memory DC Into The On-Screen DC pDC->BitBlt(LeftTop.x,LeftTop.y,BMPInfo.bmWidth,BMPInfo.bmHeight,&DCMemory,0,0,SRCCOPY);<!-- SIPO <DP n="28"> --><dp n="d28"/> DCMemory.SelectObject(pOldBitmap);∥(As Shown In MSDN Example...) } else { TRACE0(″ERRORCan Not Find The Bitmap Resource\n″); return(FALSE); } return(TRUE); } ∥----------------------------------------------------------------------------- ∥DoesGet The Original Picture Pixel Size(Ignor What Current DC Is Using) ∥~~~~ Pointer To a Device Context Is Needed For Pixel Calculation, ∥ ∥ Also Updates The Class′s Height And Width Properties, ∥ (Coz Till Now We Had No Device Context To Work With...96 DPI Assumed) ∥ ∥InPut The Client DC(Needed To Check The Size Of The Pixels) ∥~~~~~ ∥ ∥OutPutTRUE If Succeeded... ∥~~~~~~ ∥----------------------------------------------------------------------------- BOOL CPicture∷UpdateSizeOnDC(CDC*pDC) ∥====================================================================== { if(pDC==NULL‖m_IPicture==NULL){m_Height=0;m_Width=0;return(FALSE);}; m_IPicture->get_Height(&m_Height); m_IPicture->get_Width(&m_Width); ∥Get Current DPI-Dot Per Inch int CurrentDPI_X=pDC->GetDeviceCaps(LOGPIXELSX); int CurrentDPI_Y=pDC->GetDeviceCaps(LOGPIXELSY); ∥Use a″Standard″Print(When Printing) if(pDC->IsPrinting()) { CurrentDPI_X=96; CurrentDPI_Y=96; } m_Height=MulDiv(m_Height,CurrentDPI_Y,HIMETRIC_INCH); m_Width =MulDiv(m_Width,CurrentDPI_X,HIMETRIC_INCH); return(TRUE); }
权利要求
1、一种猪肉颜色分级仪器,包括图像采集设备和猪肉颜色分级软件,其特征在于
(1)图像获取设备包括图像采集室4、数码相机5
图像采集室4为直径为600mm的半球形耐高温材料制成,内壁涂成白色,4个50W卤素灯1等间距安装于图像采集室4的底部,图像采集室4内的载样台2面为用细砂布打磨过的黑色橡胶板,样品3置于橡胶板上,图像采集室4顶端开一直径为45mm圆孔;
选用CANON-PowerShotA70数码相机5,镜头穿过于图像采集室4顶圆孔;
(2)猪肉颜色分级软件
猪肉颜色计算机分级软件由图像输入控制模块、图像分割与识别模块、图像颜色特征参数提取模块、猪肉颜色等级输出模块组成
a、图像输入控制模块可以自动打开数码相机5镜头、自动拍摄样品3的彩色图像;
b、图像分割与识别模块用于对输入的彩色图像进行去噪、去背景、边缘提取,最终获取猪肉图像的有效特征颜色提取区域;
c、图像颜色特征参数提取模块用于对图像分割与识别模块获取的有效颜色提取区域提取图像的颜色特征参数,包括红色R、绿色G、蓝色B、色彩H、饱和度S、亮度V;
d、猪肉颜色等级输出模块用于调用猪肉颜色等级模型猪肉颜色等级G=4.62+6.63*S-10.20*V,输出猪肉颜色级别。
全文摘要
本项发明“猪肉颜色分级仪”属于农产品质量自动分级领域,包括图像采集设备和猪肉颜色分级软件。图像采集室4为直径为600mm的半球形耐高温材料制成,内壁涂成白色,4个50W卤素灯1等间距安装于图像采集室4的底部,样品3置于图像采集室4内的载样台2上,选用CANON-Power Shot A70数码相机5,镜头穿过于图像采集室4顶圆孔;分级软件由图像输入控制模块、图像分割与识别模块、图像颜色特征参数提取模块、猪肉颜色等级输出模块组成,猪肉颜色等级G=4.62+6.63*S-10.20*V。本发明可以将猪肉按照猪肉颜色分级标准进行计算机在线分级,指导猪肉“按级论价”,适用于超市零售。
文档编号G01N21/84GK1619295SQ20041009890
公开日2005年5月25日 申请日期2004年12月10日 优先权日2004年12月10日
发明者徐幸莲, 彭增起, 江龙建 申请人:南京农业大学