<ww:select 标签只读

本文详细介绍了在Struts2框架中如何通过HTML代码控制s:select标签使其只读,同时探讨了这种方法是否适用于s:radio标签,并提供了一个实际应用示例。

struts2中如何使s:select标签只读

在开发openjweb平台期间遇到这样一个问题,在编辑页面中,状态位字段是由系统设置的,不应该由人工设置,所以状态位字段

应该显示出来但不允许被编辑,使用struts2的<s:select>标签不具有disabled属性,除非将theme设置为simple才可以使用disabled,那么如果不使用simple的theme还有其他办法使select下拉框只读吗?从网上找到了一个办法,大致的思路就是

不让下拉框获得焦点,见下面的html代码:

<span onmousemove="this.setCapture();" onmouseout="this.releaseCapture();" onfocus="this.blur();">
  
    <s:select key="DmsDocument.docZtSpec"   name="editEntity.docZtSpec"  list="#request['map'].docZtSpec" listKey="code" listValue="name" emptyOption="true"   />
    </span>

上面的<span>标签控制了不让select下拉框获得焦点,试验了一下还真管用,那么<s:radio>大概也可以用这种方式控制只读吧,也许是可以的.
请详细分析下面代码<tr class="b"> <td>RunCard Category:</td> <td colspan="3"><#--@ww.select name="'requestForm.ercCategory'" list="{'Rework(<3 lots for one case with same reason)','Normal Condition Split(split on qualified comparison or split within spec)','Add Measurement','For Customer Request','Input the STR Number','Expriment on scrap wafer(<1 lot and must scrap in 3 stages after experiment)','Expriment on scrap wafer(<1 lot and must change lot type to engineering lot type before experiment)'}" headerKey="'Please Select'" headerValue="'Please Select'" onchange="'reloadFormForErcCategory()'" emptyOption="false" theme="'simple'"/--> <#if requestForm.ercCategory?if_exists=="STR" || requestForm.ercCategory?if_exists=="MSTR"> <select name="requestForm.ercCategory"> <option value="${requestForm.ercCategory?if_exists}">${requestForm.ercCategory}</option> </select> <#else> <select name="requestForm.ercCategory" onchange="reloadFormForErcCategory(this)" <#if requestForm.formType?if_exists=="Scan Defect">disabled=true</#if>> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Normal Condition Split"> selected="selected"</#if></#if> value="Normal Condition Split">Normal Condition Split(split on qualified comparison or split within spec)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Rework"> selected="selected"</#if></#if> value="Rework">Rework(<3 lots for one case with same reason)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Add Measurement" || requestForm.ercCategory=="need reposition"> selected="selected"</#if></#if> value="need reposition"> Add Measurement(Normal, need fill reposition step information)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="no reposition"> selected="selected"</#if></#if> value="no reposition">Add Measurement( Scan defect without reposition step)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="For Customer Request"> selected="selected"</#if></#if> value="For Customer Request">For Customer Request(Pls input the EN number)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Input the STR Number"> selected="selected"</#if></#if> value="Input the STR Number">For STR/MSTR lots(Pls input the effective STR or MSTR number)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Experiment on scrap wafer"> selected="selected"</#if></#if> value="Experiment on scrap wafer">Experiment on scrap wafer(<1 lot and must scrap in 3 stages after experiment)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Experiment on production wafer"> selected="selected"</#if></#if> value="Experiment on production wafer">Experiment on production wafer(<1 lot and must change lot type to engineering lot type before experiment)</option> </#if> </select> </td> </tr>
最新发布
09-17
请分析下面代码:<script> function getHoldLotInfo(){ <#if requestForm.formType!="Scan Defect"> document.forms['updateRequestForm'].elements["requestForm.ercStepNo"].value=""; </#if> checkRuncardStatus(); //if(checkRuncardStatus()){ var form = document.forms['updateRequestForm']; var lotId = form.elements["requestForm.lotId"].value; var holdStepNo= form.elements["requestForm.holdStepNo"].value; if(lotId==""){alert("Please key-in one LotId");return false;} if(holdStepNo==""){ form.action="updateHoldLotInfo.action"; form.submit();alert("Please key-in Hold Step No#:");} if (lotId.indexOf(" ")>0){alert("Lot Id is not allowed space!"); return false;} form.action="updateHoldLotInfo.action"; form.submit(); //} } function clearLotInfo(){ checkRuncardStatus(); //if(checkRuncardStatus()){ var form = document.forms['updateRequestForm']; var element=form.elements["requestForm.lotId"]; element.value=element.value.toUpperCase(); var lotId =element.value; if("${requestForm.lotId?if_exists}"!=""){ if(lotId!="${requestForm.lotId?if_exists}"){ form.action="updateFormToClearLotInfo.action"; form.submit(); } } // } } function clearHoldLotInfo(field){ checkRuncardStatus(); //if(checkRuncardStatus()){ var form = document.forms['updateRequestForm']; if("${requestForm.holdStepNo?if_exists}"!=""){ if(field.value!="${requestForm.holdStepNo?if_exists}"){ form.action="updateFormToClearLotInfo.action"; field.focus(); field.select(); form.submit(); }} } </script> <tr> <th colspan="4">Lot Information</th> </tr> <tr class="b"> <td>* Lot Id:</td> <td> <input type="text" name="requestForm.lotId" onchange="clearLotInfo()" value="<@ww.property value="requestForm.lotId"/>" <#if requestForm.caseNo?has_content ||requestForm.haveQtime?has_content ||requestForm.status!="DRAFT"||requestForm.ercCategory?if_exists =='STR'||requestForm.ercCategory?if_exists =='MSTR'> readonly="true" disabled="true"</#if> size="20"><#--@ww.textfield name="'requestForm.lotId'" size="20" onchange="'clearLotInfo()'" disabled="'true'" theme="'simple'"/--> </td> <td>* Hold Step No:</td> <td><input type="text" name="requestForm.holdStepNo" onchange="clearHoldLotInfo(this);" value="<@ww.property value="requestForm.holdStepNo"/>" <#if requestForm.caseNo?has_content||requestForm.haveQtime?has_content || requestForm.status!="DRAFT"> readonly="true" disabled="true"</#if> size="20"><#--@ww.textfield name="'requestForm.holdStepNo'" size="20" theme="'simple'"/-->  <input type="button" value="Go" onclick="getHoldLotInfo();" <#if requestForm.caseNo?has_content||requestForm.haveQtime?has_content ||requestForm.status!="DRAFT"> style="display:none"</#if>></td> </tr> <tr class="b"> <td>Step Id:</td> <td>${requestForm.lotStepId?if_exists}</td> <td>Stage Id:</td> <td>${requestForm.lotStageId?if_exists}</td> </tr> <tr class="b"> <td>Product Id:</td> <td>${requestForm.prodId?if_exists}</td> <td>Description:</td> <td>${requestForm.description?if_exists}</td> </tr> <tr class="b"> <td>RC Wafer QTY:</td> <td>${requestForm.waferIds?if_exists}</td> <td>Fab Area:</td> <td>${requestForm.fabArea?if_exists}</td> </tr> <tr class="b"> <td>Lot Category:</td> <td>${requestForm.lotCategory?if_exists}</td> <td></td> <td></td> </tr> <tr class="b"> <td colspan="4" width=100%> <table width=100%> <#if requestForm?has_content> <#if requestForm.qtimeStrEnds?has_content > <tr style="display:none"> <td> </TD> </tr> <tr> <th colspan="9">QTimeInfo</th> </tr> <TR> <TD class=csslabel>Plan ID </TD> <TD class=csslabel>Plan Ver </TD> <TD class=csslabel>StrStepSeq</TD> <TD class=csslabel>EndStepSeq</TD> <TD class=csslabel>IntervalTime</TD> <TD class=csslabel>ControlType</TD> <TD class=csslabel>ExpireAction</TD> <TD class=csslabel>mpsStepSeq</TD> <TD class=csslabel>handleMode</TD> </TR> <#list requestForm.qtimeStrEnds as qtimeStr> <TR> <TD class=csslabel>${qtimeStr.planId?if_exists}</TD> <TD class=csslabel>${qtimeStr.planVer?if_exists}</TD> <TD class=csslabel>${qtimeStr.strStepSeq?if_exists}</TD> <TD class=csslabel>${qtimeStr.endStepSeq?if_exists}</TD> <TD class=csslabel>${qtimeStr.intervalTime?if_exists}</TD> <TD class=csslabel>${qtimeStr.controlType?if_exists}</TD> <TD class=csslabel>${qtimeStr.expireAction?if_exists}</TD> <TD class=csslabel>${qtimeStr.mpsStepSeq?if_exists}</TD> <TD class=csslabel> <#if requestForm.formType=="Auto Reposition Step"> <@ww.select name="'requestForm.qtimeStrEnds[${qtimeStr_index}].handleMode'" list="{'Ignore','NULL'}" emptyOption="false" theme="'simple' " /> <#else> <@ww.select name="'requestForm.qtimeStrEnds[${qtimeStr_index}].handleMode'" list="{'NULL','Ignore'}" emptyOption="false" theme="'simple' " onchange="'if (\"Ignore\"==this.value)alert(\"When Ignore Select,This Q.T will delete at the beginning of runcard start\");'" /> </#if> </TD> </TR> </#list> </#if> </#if> </table> </td> </tr>
09-16
请详细逐行分析下面代码:<script> String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g, ""); } function reloadFormForErcCategory(object){ /*remove the lot type check var value=object.value; var lotType="${requestForm.lotType?default('')?if_exists}"; if(lotType=="P" | lotType=="R" | lotType=="M" |lotType=="B" |lotType=="E1" |lotType=="E2"|lotType=="E3" |lotType=="E9"){ if(value!="Input the STR Number" && value!="STR" && value!="MSTR") { alert("Because the lotType is "+lotType+ ". Please select 'the For STR/MSTR lots(Pls input the effective STR or MSTR number)' in RunCard Category, and input the STR# ! "); return false; } }*/ checkRuncardStatus(); var form = document.forms['updateRequestForm']; form.action="saveRequestForm.action"; form.submit(); } function IsChar(s) { var Number ="0123456789.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\":;.,?'|-_ "; for (i = 0; i < s.length;i++) { // Check that current character isn't whitespace. var c = s.charAt(i); if (c!="\r" && c!="\n"&&Number.indexOf(c) == -1) {return false;} } return true } function realLength (str) { return str.replace(/[^\x00-\xff]/g,"**").length; } function CheckChar(theField) { var value=theField.value; var reg=/\s/g; var stringLength=value.replace(reg,""); if(stringLength.length>150){ alert("最多150个字符!"); theField.focus(); return false; } if(stringLength.length!=realLength(stringLength)) { alert("只能输入英文或数字,请不要输入中文或特殊字符!"); theField.value=""; theField.focus(); return false; } if (!IsChar(theField.value)) { alert("只能输入英文或数字,请不要输入中文或特殊字符!"); theField.value=""; theField.focus(); } } </script> <tr> <th colspan="4">RunCard Header</th> </tr> <tr class="b"> <td>RunCard Category:</td> <td colspan="3"><#--@ww.select name="'requestForm.ercCategory'" list="{'Rework(<3 lots for one case with same reason)','Normal Condition Split(split on qualified comparison or split within spec)','Add Measurement','For Customer Request','Input the STR Number','Expriment on scrap wafer(<1 lot and must scrap in 3 stages after experiment)','Expriment on scrap wafer(<1 lot and must change lot type to engineering lot type before experiment)'}" headerKey="'Please Select'" headerValue="'Please Select'" onchange="'reloadFormForErcCategory()'" emptyOption="false" theme="'simple'"/--> <#if requestForm.ercCategory?if_exists=="STR" || requestForm.ercCategory?if_exists=="MSTR"> <select name="requestForm.ercCategory"> <option value="${requestForm.ercCategory?if_exists}">${requestForm.ercCategory}</option> </select> <#else> <select name="requestForm.ercCategory" onchange="reloadFormForErcCategory(this)" <#if requestForm.formType?if_exists=="Scan Defect">disabled=true</#if>> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Normal Condition Split"> selected="selected"</#if></#if> value="Normal Condition Split">Normal Condition Split(split on qualified comparison or split within spec)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Rework"> selected="selected"</#if></#if> value="Rework">Rework(<3 lots for one case with same reason)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Add Measurement" || requestForm.ercCategory=="need reposition"> selected="selected"</#if></#if> value="need reposition"> Add Measurement(Normal, need fill reposition step information)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="no reposition"> selected="selected"</#if></#if> value="no reposition">Add Measurement( Scan defect without reposition step)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="For Customer Request"> selected="selected"</#if></#if> value="For Customer Request">For Customer Request(Pls input the EN number)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Input the STR Number"> selected="selected"</#if></#if> value="Input the STR Number">For STR/MSTR lots(Pls input the effective STR or MSTR number)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Experiment on scrap wafer"> selected="selected"</#if></#if> value="Experiment on scrap wafer">Experiment on scrap wafer(<1 lot and must scrap in 3 stages after experiment)</option> <option <#if requestForm.ercCategory?has_content> <#if requestForm.ercCategory=="Experiment on production wafer"> selected="selected"</#if></#if> value="Experiment on production wafer">Experiment on production wafer(<1 lot and must change lot type to engineering lot type before experiment)</option> </#if> </select> </td> </tr> <#if requestForm.ercCategory?exists> <#if requestForm.ercCategory=="For Customer Request"> <tr class="b"> <td>* EN#:</td> <td colspan="3"><@ww.textfield name="'requestForm.strEnNo'" onchange="'javascript:this.value = this.value.trim();'" size="20" theme="'simple'"/></td> </tr> </#if> <#if requestForm.ercCategory=="Input the STR Number"> <tr class="b"> <td>* STR#:</td> <td colspan="3"><@ww.textfield name="'requestForm.strEnNo'" onchange="'javascript:this.value = this.value.trim();'" size="20" theme="'simple'"/></td> </tr> </#if> <#if requestForm.ercCategory=="STR" || requestForm.ercCategory=="MSTR"> <tr class="b"> <td>* STR#:</td> <td colspan="3">${requestForm.strEnNo?if_exists}</td> </tr> </#if> </#if> <tr class="b"> <td>* Purpose:</td> <td colspan="3"><@ww.textarea name="'requestForm.purpose'" value="requestForm.purpose" cols="65" rows="3" onblur="'CheckChar(this)'" theme="'simple'"/></td> </tr> <tr class="b"> <td>* Need to Check:</td> <td colspan="3"><@ww.radio name="'requestForm.needCheck'" list="{'Yes','No'}" theme="'simple'" value="'${requestForm.needCheck?default('Yes'?if_exists)}'" required="true"/>       <font color="red">(Yes - will check product Id consistency with MES)</font> </td> </tr>
09-17
#include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/features/esf.h> // esf特征头文件 #include <pcl\common\common.h> #include <pcl/common/angles.h> #include <pcl/common/centroid.h> #include <pcl/registration/icp.h> // icp算法 #include <pcl/registration/registration.h> #include <pcl/registration/correspondence_rejection_one_to_one.h> // 一对一删除重复点对 #include <pcl/common/file_io.h> // 批量处理头文件 #include <pcl/console/time.h> // 利用控制台计算时间 #include <pcl/common/distances.h> // 扇形分区 std::pair <std::vector<pcl::PointCloud<pcl::PointXYZI>>, std::vector<pcl::PointCloud<pcl::PointXYZI>>> sectorPartition(pcl::PointCloud<pcl::PointXYZI>::Ptr& source, pcl::PointCloud<pcl::PointXYZI>::Ptr& target, int sectorNum = 12) { // 计算质心 Eigen::Vector4f centroid; // 质心 pcl::compute3DCentroid(*source, centroid); // 齐次坐标,(c0,c1,c2,1) float Xo = centroid[0]; float Zo = centroid[2]; float Xi = 0.0; float Zi = 0.0; float rad = 0.0; // 点到质心的弧度 std::vector<float>sourceDeg(source->size(), -1.0); // 遍历源点云 for (size_t i = 0; i < source->size(); ++i) { Xi = source->points[i].x; Zi = source->points[i].z; // 点到质心的弧度 rad = atan2(Xi - Xo, Zi - Zo); if (rad < 0) { sourceDeg[i] = pcl::rad2deg(rad) + 360; } else { sourceDeg[i] = pcl::rad2deg(rad); } } std::vector<float>targetDeg(target->size(), -1.0); // 遍历目标点云 for (size_t i = 0; i < target->size(); ++i) { Xi = target->points[i].x; Zi = target->points[i].z; // 点到质心的弧度 rad = atan2(Xi - Xo, Zi - Zo); if (rad < 0) { targetDeg[i] = pcl::rad2deg(rad) + 360; } else { targetDeg[i] = pcl::rad2deg(rad); } } float sectorSize = 360 / (1.0 * sectorNum); // 存储分区点的容器 std::vector<pcl::PointCloud<pcl::PointXYZI>> sourceInSector(sectorNum); std::vector<pcl::PointCloud<pcl::PointXYZI>> targetInSector(sectorNum); // 计算源点云任一点所在的分区 for (int i = 0; i < source->size(); ++i) { int sectorID = std::floor(sourceDeg[i] / sectorSize); sourceInSector[sectorID].push_back(source->points[i]); } // 计算目标点云任一点所在的分区 for (int i = 0; i < target->size(); ++i) { int sectorID = std::floor(targetDeg[i] / sectorSize); targetInSector[sectorID].push_back(target->points[i]); } std::pair <std::vector<pcl::PointCloud<pcl::PointXYZI>>, std::vector<pcl::PointCloud<pcl::PointXYZI>>> sectorLabel(sourceInSector, targetInSector); return sectorLabel; } // 计算断面扇形分区配准偏差 void calCrossRegistrationDeviation(pcl::PointCloud<pcl::PointXYZI>::Ptr& baseCloud, pcl::PointCloud<pcl::PointXYZI>::Ptr& computedCloud, double& SD) { pcl::PointCloud<pcl::PointXYZI>::Ptr cloudSizeLarge(new pcl::PointCloud<pcl::PointXYZI>); pcl::PointCloud<pcl::PointXYZI>::Ptr cloudSizeSmall(new pcl::PointCloud<pcl::PointXYZI>); if (baseCloud->points.size() > computedCloud->points.size()) { cloudSizeLarge = baseCloud; cloudSizeSmall = computedCloud; } else { cloudSizeLarge = computedCloud; cloudSizeSmall = baseCloud; } std::vector<double> deviation; // 最临近点距离传递至强度 pcl::KdTreeFLANN<pcl::PointXYZI> kdtree; kdtree.setInputCloud(cloudSizeLarge); //采样后根据最邻近点提取的样本点下标索引 pcl::PointIndicesPtr inds = std::shared_ptr<pcl::PointIndices>(new pcl::PointIndices()); for (size_t i = 0; i < cloudSizeSmall->points.size(); i++) { pcl::PointXYZI searchPoint; searchPoint.x = cloudSizeSmall->points[i].x; searchPoint.y = cloudSizeSmall->points[i].y; searchPoint.z = cloudSizeSmall->points[i].z; searchPoint.intensity = cloudSizeSmall->points[i].intensity; int K = 1;// 最近邻搜索 std::vector<int> pointIdxNKNSearch(K); std::vector<float> pointNKNSquaredDistance(K); if (kdtree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0) { if (pointNKNSquaredDistance[0] < 0.01) { deviation.push_back(pointNKNSquaredDistance[0]); } } } // 求和 double sum = 0; for (double value : deviation) { sum += value; } // 计算均值 double mean = sum / deviation.size(); // 计算方差 double squaredDiffSum = 0.0; for (double value : deviation) { squaredDiffSum += std::pow(value - mean, 2); } double variance = squaredDiffSum / (deviation.size() - 1); // 计算标准差 if (deviation.size() == 0) { SD = -1; } else { SD = std::sqrt(variance); } } // 计算最终配准误差 void calFinalRegistrationRMSE(pcl::PointCloud<pcl::PointXYZI>::Ptr& baseCloud, pcl::PointCloud<pcl::PointXYZI>::Ptr& computedCloud, double& RMSE) { // 获取匹配点对 pcl::registration::CorrespondenceEstimation<pcl::PointXYZI, pcl::PointXYZI>core; core.setInputSource(baseCloud); core.setInputTarget(computedCloud); pcl::Correspondences corres; core.determineCorrespondences(corres, 0.012);// 确定输入点云与目标点云之间的距离 12 mm // 一对一删除重复点对 pcl::CorrespondencesPtr correspondencesRejOneToOne(new pcl::Correspondences); pcl::registration::CorrespondenceRejectorOneToOne corrRejOneToOne; corrRejOneToOne.getRemainingCorrespondences(corres, corres);// 一对一删除重复点对 float sum = 0.0; for (size_t i = 0; i < corres.size(); ++i) { sum += corres[i].distance; } if (corres.size() == 0) { RMSE = -1.0; } else { RMSE = sqrt(sum / corres.size()); // 均方根误差; } } // ICP配准 void ICP(pcl::PointCloud<pcl::PointXYZI>::Ptr& oldSection, pcl::PointCloud<pcl::PointXYZI>::Ptr& baseSection, pcl::PointCloud<pcl::PointXYZI>::Ptr& newSection, int maximumIterateTime, float maxCorrespondenceDistance, float registrationAccuracy, Eigen::Matrix4f& transform, double& SD) { // ICP精配准 pcl::PointCloud<pcl::PointXYZI>::Ptr ICPCrossIn = oldSection; // 初始化ICP对象 pcl::IterativeClosestPoint<pcl::PointXYZI, pcl::PointXYZI> icp; // KD树加速搜索 pcl::search::KdTree<pcl::PointXYZI>::Ptr tree1(new pcl::search::KdTree<pcl::PointXYZI>); pcl::search::KdTree<pcl::PointXYZI>::Ptr tree2(new pcl::search::KdTree<pcl::PointXYZI>); tree1->setInputCloud(ICPCrossIn); tree2->setInputCloud(baseSection); icp.setSearchMethodSource(tree1); icp.setSearchMethodTarget(tree2); icp.setInputSource(ICPCrossIn); // 源点云 icp.setInputTarget(baseSection); // 目标点云 icp.setTransformationEpsilon(1e-10); // 为终止条件设置最小转换差异 icp.setMaxCorrespondenceDistance(maxCorrespondenceDistance); // 设置对应点对之间的最大距离 icp.setMaximumIterations(maximumIterateTime); // 最大迭代次数 // 设置收敛条件是均方误差和小于阈值, 停止迭代; icp.setEuclideanFitnessEpsilon(registrationAccuracy); //使用相互对应关系 icp.setUseReciprocalCorrespondences(true); pcl::PointCloud<pcl::PointXYZI>::Ptr ICPcloud(new pcl::PointCloud<pcl::PointXYZI>); icp.align(*ICPcloud); // ICP依次转换对象 transform = icp.getFinalTransformation(); pcl::transformPointCloud(*ICPCrossIn, *ICPcloud, transform); newSection = ICPcloud; calCrossRegistrationDeviation(newSection, baseSection, SD); } // 计算ESF特征 pcl::PointCloud<pcl::ESFSignature640>::Ptr ESFEstimation(pcl::PointCloud<pcl::PointXYZI>::Ptr& object) { // Object for storing the ESF descriptor. pcl::PointCloud<pcl::ESFSignature640>::Ptr descriptor(new pcl::PointCloud<pcl::ESFSignature640>); // ESF estimation object. pcl::ESFEstimation<pcl::PointXYZI, pcl::ESFSignature640> esf; esf.setInputCloud(object); //esf.setKSearch(10); esf.compute(*descriptor); return descriptor; } // 分区加权ICP配准 pcl::PointCloud<pcl::PointXYZI>::Ptr blockICP(pcl::PointCloud<pcl::PointXYZI>::Ptr& source, pcl::PointCloud<pcl::PointXYZI>::Ptr& target, float& maxCorrespondenceDistance, int& sectorNum, double& frmse) { // 扇形分区 auto sectorResults = sectorPartition(source, target, sectorNum); // 分区配准 std::vector<Eigen::Matrix4f>RotaionGroup; std::map<int, pcl::PointCloud<pcl::PointXYZI>::Ptr> newSectionICP; std::vector<double>weight; for (int i = 0; i < sectorNum; i++) { if (sectorResults.first[i].empty() || sectorResults.second[i].empty()) { continue; } // 计算ESF特征描述 auto sourceFeature = ESFEstimation(sectorResults.first[i].makeShared()); auto targetFeature = ESFEstimation(sectorResults.second[i].makeShared()); float sumAB = 0.0; float sumAA = 0.0; float sumBB = 0.0; for (int k = 0; k < 640; ++k) { float Vik = sourceFeature->points[0].histogram[k]; float Vjk = targetFeature->points[0].histogram[k]; sumAB += Vik * Vjk; sumAA += Vik * Vik; sumBB += Vjk * Vjk; } // 计算余弦相似度 float sim = sumAB / static_cast<float>(sqrt(sumAA) * sqrt(sumBB)); if (sim < 0.9) { //std::cout << "第" << i << "个分区的匹配点对不够" << std::endl; continue; } // 配准 Eigen::Matrix4f Rotation; double SD = 0.0; ICP(sectorResults.first[i].makeShared(), sectorResults.second[i].makeShared(), newSectionICP[i], 100, maxCorrespondenceDistance, 0.001, Rotation, SD); if (SD <= 0) { //std::cout << "第" << i << "个扇区配准失败" << std::endl; continue; } RotaionGroup.push_back(Rotation); weight.push_back(1.0 / SD); } // 加权获得最后的变换矩阵 Eigen::Matrix4f bestRotaion = Eigen::Matrix4f::Zero(4, 4); double weightSum = 0; for (int i = 0; i < weight.size(); i++) { weightSum += weight[i]; } for (int i = 0; i < weight.size(); i++) { bestRotaion += (weight[i] / weightSum) * RotaionGroup[i]; } pcl::PointCloud<pcl::PointXYZI>::Ptr registResult(new pcl::PointCloud<pcl::PointXYZI>); pcl::transformPointCloud(*source, *registResult, bestRotaion); // 计算最终配准误差 calFinalRegistrationRMSE(registResult, target, frmse); return registResult; } int main() { pcl::console::TicToc time; pcl::PointCloud<pcl::PointXYZI>::Ptr source(new pcl::PointCloud<pcl::PointXYZI>); pcl::io::loadPCDFile<pcl::PointXYZI>("WW//228//source_slice_228.pcd", *source); pcl::PointCloud<pcl::PointXYZI>::Ptr target(new pcl::PointCloud<pcl::PointXYZI>); pcl::io::loadPCDFile<pcl::PointXYZI>("WW//228//target_slice_228.pcd", *target); time.tic(); float maxCorrespondenceDistance = 0.8; // 匹配点对之间的最大距离 int sectorNum = 1; // 分区个数 double frmse = 0.0; // 配准误差 int maxSectorNum = 6; // 最大分区个数 float m_errorTh = 0.00001; // 最小转换差异 double errorMin = FLT_MAX; int bestSegNum = 1; float error = std::numeric_limits<float>::infinity(); pcl::PointCloud<pcl::PointXYZI>::Ptr registResult(new pcl::PointCloud<pcl::PointXYZI>); while (error > m_errorTh && sectorNum <= maxSectorNum) { float lastError = error; registResult = blockICP(source, target, maxCorrespondenceDistance, sectorNum, frmse); //std::cout << "分区为" << sectorNum << "时的配准误差为;" << frmse << std::endl; error = frmse; if (frmse <= 0) { break; } if (error < errorMin) { errorMin = error; bestSegNum = sectorNum; } sectorNum++; // 前后两次迭代的误差小于1e-4,则停止迭代 if ((error <= lastError) && (lastError - error < m_errorTh)) { break; } } std::cout << "最佳分块为:" << bestSegNum << std::endl; registResult = blockICP(source, target, maxCorrespondenceDistance, bestSegNum, frmse); std::cout << "算法耗时:" << time.toc() << " ms" << std::endl; std::cout << "最佳分块配准误差为:" << frmse << std::endl; pcl::io::savePCDFileBinary("WW//result//source_slice_1427reg.pcd", *registResult); return 0; } 代码封装成类,.h和.cpp分开保存,命名为:BlockWeightedRegistration
08-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值