|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "OpencvImgShell.h"
|
|
|
|
|
|
|
|
|
|
#include "IntensityContrastDefinationControl.h"
|
|
|
|
|
|
|
|
|
|
#include "IntensityControl.h"
|
|
|
|
|
#include "ContrastControl.h"
|
|
|
|
|
#include "DefinitionControl.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ͨ<><CDA8><EFBFBD>鱨<EFBFBD>ṹ<EFBFBD><E1B9B9><EFBFBD><EFBFBD><EFBFBD>ȶԱȶ<D4B1><C8B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȿ<EFBFBD><C8BF><EFBFBD>
|
|
|
|
|
BOOL QBStru_ICD_Control(QBStru *qbData, int Idegree, int Cdegree, int Ddegree, BOOL bSrcFirst)
|
|
|
|
|
{
|
|
|
|
|
// <20><>ֵ<EFBFBD>ж<EFBFBD>
|
|
|
|
|
if (qbData == NULL)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ͼ<><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7>ֱ<EFBFBD>ӷ<EFBFBD><D3B7><EFBFBD>false
|
|
|
|
|
if (qbData->imgValid == 0)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ȴ<EFBFBD><C8B4><EFBFBD>srcImg
|
|
|
|
|
if (bSrcFirst == TRUE)
|
|
|
|
|
{
|
|
|
|
|
if (qbData->image.srcImg.buff != NULL &&
|
|
|
|
|
qbData->image.srcImg.ImgWidth > 0 && // srcImg <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤
|
|
|
|
|
qbData->image.srcImg.ImgHeight > 0 && // srcImg <20>߶<EFBFBD><DFB6><EFBFBD>֤
|
|
|
|
|
(qbData->image.srcImg.bitcount == 24 || qbData->image.srcImg.bitcount == 8))
|
|
|
|
|
{
|
|
|
|
|
qbData->image.dstImg.ImgWidth = qbData->image.srcImg.ImgWidth;
|
|
|
|
|
qbData->image.dstImg.ImgHeight = qbData->image.srcImg.ImgHeight;
|
|
|
|
|
qbData->image.dstImg.bitcount = qbData->image.srcImg.bitcount;
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ռ<EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>
|
|
|
|
|
int lineByte = (qbData->image.dstImg.ImgWidth * qbData->image.dstImg.bitcount / 8);
|
|
|
|
|
|
|
|
|
|
// λͼ<CEBB><CDBC><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD>С
|
|
|
|
|
int imgBufSize = qbData->image.dstImg.ImgHeight * lineByte;
|
|
|
|
|
|
|
|
|
|
if (qbData->image.dstImg.buff != NULL)
|
|
|
|
|
{
|
|
|
|
|
delete [] qbData->image.dstImg.buff;
|
|
|
|
|
qbData->image.dstImg.buff = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qbData->image.dstImg.buff = new unsigned char[imgBufSize];
|
|
|
|
|
|
|
|
|
|
return ImgStru_ICD_Control(&qbData->image.srcImg, &qbData->image.dstImg, Idegree, Cdegree, Ddegree);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if (qbData->image.dstImg.buff != NULL &&
|
|
|
|
|
qbData->image.dstImg.ImgWidth > 0 && // dstImg <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤
|
|
|
|
|
qbData->image.dstImg.ImgHeight > 0 && // dstImg <20>߶<EFBFBD><DFB6><EFBFBD>֤
|
|
|
|
|
(qbData->image.dstImg.bitcount == 24 || qbData->image.dstImg.bitcount == 8))
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>dstImg<6D><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD>dstImg
|
|
|
|
|
return ImgStru_ICD_Control(&qbData->image.dstImg, &qbData->image.dstImg, Idegree, Cdegree, Ddegree);
|
|
|
|
|
}
|
|
|
|
|
else // srcImg dstImg<6D><67><EFBFBD><EFBFBD>Ч
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// <20>ȿ<EFBFBD>dstImg<6D>Ƿ<EFBFBD><C7B7><EFBFBD>Ч
|
|
|
|
|
if (qbData->image.dstImg.buff != NULL &&
|
|
|
|
|
qbData->image.dstImg.ImgWidth > 0 && // dstImg <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤
|
|
|
|
|
qbData->image.dstImg.ImgHeight > 0 && // dstImg <20>߶<EFBFBD><DFB6><EFBFBD>֤
|
|
|
|
|
(qbData->image.dstImg.bitcount == 24 || qbData->image.dstImg.bitcount == 8))
|
|
|
|
|
{
|
|
|
|
|
return ImgStru_ICD_Control(&qbData->image.dstImg, &qbData->image.dstImg, Idegree, Cdegree, Ddegree);
|
|
|
|
|
}else
|
|
|
|
|
if (qbData->image.srcImg.buff != NULL &&
|
|
|
|
|
qbData->image.srcImg.ImgWidth > 0 && // srcImg <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤
|
|
|
|
|
qbData->image.srcImg.ImgHeight > 0 && // srcImg <20>߶<EFBFBD><DFB6><EFBFBD>֤
|
|
|
|
|
(qbData->image.srcImg.bitcount == 24 || qbData->image.srcImg.bitcount == 8))
|
|
|
|
|
{
|
|
|
|
|
qbData->image.dstImg.ImgWidth = qbData->image.srcImg.ImgWidth;
|
|
|
|
|
qbData->image.dstImg.ImgHeight = qbData->image.srcImg.ImgHeight;
|
|
|
|
|
qbData->image.dstImg.bitcount = qbData->image.srcImg.bitcount;
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ռ<EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>
|
|
|
|
|
int lineByte = (qbData->image.dstImg.ImgWidth * qbData->image.dstImg.bitcount / 8);
|
|
|
|
|
|
|
|
|
|
// λͼ<CEBB><CDBC><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD>С
|
|
|
|
|
int imgBufSize = qbData->image.dstImg.ImgHeight * lineByte;
|
|
|
|
|
|
|
|
|
|
qbData->image.dstImg.buff = new unsigned char[imgBufSize];
|
|
|
|
|
|
|
|
|
|
return ImgStru_ICD_Control(&qbData->image.srcImg, &qbData->image.dstImg, Idegree, Cdegree, Ddegree);
|
|
|
|
|
}
|
|
|
|
|
else // <20>鱨<EFBFBD>ṹ<EFBFBD><E1B9B9>srcImg <20><> dstImg <20><><EFBFBD><EFBFBD>Ч
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ImgStru<72>ṹ<EFBFBD>µ<EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD><EFBFBD>ȶԱȶ<D4B1><C8B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȿ<EFBFBD><C8BF><EFBFBD>
|
|
|
|
|
//<2F><><EFBFBD>ܣ<EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD><EFBFBD>ȶԱȶ<D4B1><C8B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȿ<EFBFBD><C8BF><EFBFBD>
|
|
|
|
|
BOOL ImgStru_ICD_Control(ImgStru* src, ImgStru* dst, int Idegree, int Cdegree, int Ddegree)
|
|
|
|
|
{
|
|
|
|
|
// src dst <20><>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD>֤
|
|
|
|
|
if (src == NULL || dst ==NULL ||
|
|
|
|
|
src->ImgWidth <=0 ||
|
|
|
|
|
src->ImgHeight <= 0 ||
|
|
|
|
|
src->bitcount <= 0 ||
|
|
|
|
|
src->buff == NULL)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(src->bitcount != 8 && src->bitcount != 24)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>Ը<EFBFBD><D4B8><EFBFBD>
|
|
|
|
|
dst->ImgWidth = src->ImgWidth;
|
|
|
|
|
dst->ImgHeight = src->ImgHeight;
|
|
|
|
|
dst->bitcount = src->bitcount;
|
|
|
|
|
dst->BoundingBox = src->BoundingBox;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>롢<EFBFBD><EBA1A2><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC>
|
|
|
|
|
IplImage* src_Img = NULL;
|
|
|
|
|
src_Img = cvCreateImage(cvSize(src->ImgWidth, src->ImgHeight), 8, src->bitcount/8);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ռ<EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>չ<EFBFBD><D5B9>4<EFBFBD>ı<EFBFBD><C4B1><EFBFBD>
|
|
|
|
|
int lineByte = (src->ImgWidth * src->bitcount / 8 + 3) / 4 * 4;
|
|
|
|
|
|
|
|
|
|
// λͼ<CEBB><CDBC><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD>С
|
|
|
|
|
unsigned int imgBufSize = static_cast<unsigned int>(src->ImgHeight * lineByte);
|
|
|
|
|
|
|
|
|
|
if (src_Img != NULL)
|
|
|
|
|
{
|
|
|
|
|
// ͼ<><CDBC><EFBFBD><EFBFBD><EFBFBD>ݸ<EFBFBD><DDB8><EFBFBD>
|
|
|
|
|
int realLineByte = (src->ImgWidth * src->bitcount / 8);
|
|
|
|
|
|
|
|
|
|
if (realLineByte == lineByte)
|
|
|
|
|
{
|
|
|
|
|
memcpy(src_Img->imageData, src->buff, imgBufSize);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < src->ImgHeight; i++)
|
|
|
|
|
{
|
|
|
|
|
memcpy(src_Img->imageData + i * lineByte, src->buff + i * realLineByte, realLineByte);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IplImage* dst_Img = NULL;
|
|
|
|
|
dst_Img = cvCreateImage(cvSize(dst->ImgWidth, dst->ImgHeight), 8, dst->bitcount/8);
|
|
|
|
|
|
|
|
|
|
if (dst_Img == NULL)
|
|
|
|
|
{
|
|
|
|
|
cvReleaseImage(&src_Img);
|
|
|
|
|
src_Img = NULL;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SAFE_DELETE_ARRAY(dst->buff);
|
|
|
|
|
dst->buff = NULL;
|
|
|
|
|
dst->buff = new unsigned char[imgBufSize];
|
|
|
|
|
|
|
|
|
|
if (dst->buff == NULL)
|
|
|
|
|
{
|
|
|
|
|
cvReleaseImage(&src_Img);
|
|
|
|
|
src_Img = NULL;
|
|
|
|
|
|
|
|
|
|
cvReleaseImage(&dst_Img);
|
|
|
|
|
dst_Img = NULL;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>IplImageICDControl<6F>㷨<EFBFBD><E3B7A8>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD>ȶԱȶ<D4B1><C8B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȿ<EFBFBD><C8BF><EFBFBD>
|
|
|
|
|
if (IplImage_ICD_Control(src_Img, dst_Img, Idegree, Cdegree, Ddegree) == TRUE)
|
|
|
|
|
{
|
|
|
|
|
cvReleaseImage(&src_Img);
|
|
|
|
|
src_Img = NULL;
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>dst_Img->imageData <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> dst->buff
|
|
|
|
|
memcpy(dst->buff, dst_Img->imageData, imgBufSize);
|
|
|
|
|
|
|
|
|
|
cvReleaseImage(&dst_Img);
|
|
|
|
|
dst_Img = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cvReleaseImage(&src_Img);
|
|
|
|
|
src_Img = NULL;
|
|
|
|
|
|
|
|
|
|
cvReleaseImage(&dst_Img);
|
|
|
|
|
dst_Img = NULL;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// OpenCV<43>ṹ<EFBFBD>µ<EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD><EFBFBD>ȶԱȶ<D4B1><C8B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȿ<EFBFBD><C8BF><EFBFBD>
|
|
|
|
|
BOOL IplImage_ICD_Control(IplImage* src, IplImage* dst, int Idegree, int Cdegree, int Ddegree)
|
|
|
|
|
{
|
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ȿ<EFBFBD><C8BF>Ƴ̶<C6B3> <20>жϺͲö<CDB2>
|
|
|
|
|
if(Idegree < 0)
|
|
|
|
|
{
|
|
|
|
|
Idegree = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(Idegree > 20)
|
|
|
|
|
{
|
|
|
|
|
Idegree = 20;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>Աȶȿ<C8B6><C8BF>Ƴ̶<C6B3> <20>жϺͲö<CDB2>
|
|
|
|
|
if(Cdegree < 0)
|
|
|
|
|
{
|
|
|
|
|
Cdegree = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(Cdegree > 20)
|
|
|
|
|
{
|
|
|
|
|
Cdegree = 20;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>жϺͲö<CDB2>
|
|
|
|
|
if(Ddegree < 0)
|
|
|
|
|
{
|
|
|
|
|
Ddegree = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(Ddegree > 20)
|
|
|
|
|
{
|
|
|
|
|
Ddegree = 20;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
int way = 0;
|
|
|
|
|
|
|
|
|
|
if (Idegree == 10 && Cdegree == 10 && Ddegree == 10) // 000
|
|
|
|
|
{
|
|
|
|
|
way = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (Idegree == 10 && Cdegree == 10 && Ddegree != 10) // 001
|
|
|
|
|
{
|
|
|
|
|
way = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (Idegree == 10 && Cdegree != 10 && Ddegree == 10) // 010
|
|
|
|
|
{
|
|
|
|
|
way = 2;
|
|
|
|
|
}
|
|
|
|
|
else if (Idegree == 10 && Cdegree != 10 && Ddegree != 10) // 011
|
|
|
|
|
{
|
|
|
|
|
way = 3;
|
|
|
|
|
}
|
|
|
|
|
else if (Idegree != 10 && Cdegree == 10 && Ddegree == 10) // 100
|
|
|
|
|
{
|
|
|
|
|
way = 4;
|
|
|
|
|
}
|
|
|
|
|
else if (Idegree != 10 && Cdegree == 10 && Ddegree != 10) // 101
|
|
|
|
|
{
|
|
|
|
|
way = 5;
|
|
|
|
|
}
|
|
|
|
|
else if (Idegree != 10 && Cdegree != 10 && Ddegree == 10) // 110
|
|
|
|
|
{
|
|
|
|
|
way = 6;
|
|
|
|
|
}
|
|
|
|
|
else if (Idegree != 10 && Cdegree != 10 && Ddegree != 10) // 111
|
|
|
|
|
{
|
|
|
|
|
way = 7;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
way = 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(way)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
cvCopy(src, dst);
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: // ֻ<><D6BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
ret = IplImageDefinitionControl(src, dst, Ddegree);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: // ֻ<><D6BB><EFBFBD>ڶԱȶ<D4B1>
|
|
|
|
|
ret = IplImageContrastControl(src, dst, Cdegree);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3:// <20>Աȶ<D4B1> + <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
if (IplImageContrastControl(src, dst, Cdegree))
|
|
|
|
|
{
|
|
|
|
|
cvCopy(dst, src);
|
|
|
|
|
ret = IplImageDefinitionControl(src, dst, Ddegree);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 4: // ֻ<><D6BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
ret = IplImageIntensityControl(src, dst, Idegree);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 5: // <20><><EFBFBD><EFBFBD> + <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
if (IplImageIntensityControl(src, dst, Idegree))
|
|
|
|
|
{
|
|
|
|
|
cvCopy(dst, src);
|
|
|
|
|
ret = IplImageDefinitionControl(src, dst, Ddegree);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 6: // <20><><EFBFBD><EFBFBD> + <20>Աȶ<D4B1>
|
|
|
|
|
if (IplImageIntensityControl(src, dst, Idegree))
|
|
|
|
|
{
|
|
|
|
|
cvCopy(dst, src);
|
|
|
|
|
ret = IplImageContrastControl(src, dst, Cdegree);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 7: // <20><><EFBFBD><EFBFBD> + <20>Աȶ<D4B1> + <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
if (IplImageIntensityControl(src, dst, Idegree))
|
|
|
|
|
{
|
|
|
|
|
if (IplImageContrastControl(dst, src, Cdegree))
|
|
|
|
|
{
|
|
|
|
|
ret = IplImageDefinitionControl(src, dst, Ddegree);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|