I'm working on a registration project, I have a chair with some objects rotating in front of a kinect.
I can have successful pairwise registration, but as expected there is some drift (result in image).
I want to use LUM, in order to have a global minimization of the accumulated error (and then "spread" it across frames), but I end up having the frames floating in the air. (code below the image)
Is this there any obvious mistake in the usage of LUM?
---I use keypoints+features, not blindly feeding LUM with full pointclouds
Why all the examples add one-directional edges and not bi-directional?
PARAM_LUM_centroidDistTHRESH = 0.30;
PARAM_LUM_MaxIterations = 100;
PARAM_LUM_ConvergenceThreshold = 0.0f;
int NeighborhoodNUMB = 2;
int FrameDistLOOPCLOSURE = 5;
PARAM_CORR_REJ_InlierThreshold = 0.020;
pcl::registration::LUM<pcl::PointXYZRGBNormal> lum;
lum.setMaxIterations( PARAM_LUM_MaxIterations );
lum.setConvergenceThreshold( PARAM_LUM_ConvergenceThreshold );
QVector< pcl::PointCloud<pcl::PointXYZRGB>::Ptr > cloudVector_ORGan_P_;
for (int iii=0; iii<totalClouds; iii++)
{
// read - iii_cloud_ORGan_P_
// transform it with pairwise registration result
cloudVector_ORGan_P_.append( iii_cloud_ORGan_P_ );
}
for (size_t iii=0; iii<totalClouds; iii++)
{
pcl::compute3DCentroid( *cloudVector_ORGan_P_[iii], centrVector[iii] );
pcl::IntegralImageNormalEstimation<pcl::PointXYZRGB,pcl::Normal> ne;
//blah blah parameters
//compute normals with *ne*
//pcl::removeNaNFromPointCloud
//pcl::removeNaNNormalsFromPointCloud
pcl::ISSKeypoint3D< pcl::PointXYZRGBNormal, pcl::PointXYZRGBNormal> keyPointDetector;
//blah balh parameters;
//keyPointDetector.compute
//then remove NAN keypoints
pcl::SHOTColorEstimationOMP< pcl::PointXYZRGBNormal,pcl::PointXYZRGBNormal,pcl::SHOT1344 > featureDescriptor;
//featureDescriptor.setSearchSurface( **ful_unorganized_cloud_in_here** );
//featureDescriptor.setInputNormals( **normals_from_above____in_here** );
//featureDescriptor.setInputCloud( **keypoints_from_above__in_here** );
//blah blah parameters
//featureDescriptor.compute
//delete NAN *Feature* + corresp. *Keypoints* with *.erase*
}
for (size_t iii=0; iii<totalClouds; iii++)
{
lum.addPointCloud( KEYptVector_UNorg_P_[iii] );
}
for (size_t iii=1; iii<totalClouds; iii++)
{
for (size_t jjj=0; jjj<iii; jjj++)
{
double cloudCentrDISTANCE = ( centrVector[iii] - centrVector[jjj] ).norm();
if ( (cloudCentrDISTANCE<PARAM_LUM_centroidDistTHRESH && qAbs(iii-jjj)<=NeighborhoodNUMB) ||
(cloudCentrDISTANCE<PARAM_LUM_centroidDistTHRESH && qAbs(iii-jjj)> FrameDistLOOPCLOSURE) )
{
int sourceID;
int targetID;
if (qAbs(iii-jjj)<=NeighborhoodNUMB) // so that connection are e.g. 0->1, 1->2, 2->3, 3->4, 4->5, 5->0
{ // not sure if it helps
sourceID = jjj;
targetID = iii;
}
else
{
sourceID = iii;
targetID = jjj;
}
*source_cloud_KEYpt_P_ = *lum.getPointCloud(sourceID);
*target_cloud_KEYpt_P_ = *lum.getPointCloud(targetID);
*source_cloud_FEATures = *FEATtVector_UNorg_P_[sourceID];
*target_cloud_FEATures = *FEATtVector_UNorg_P_[targetID];
// KeyPoint Estimation
pcl::registration::CorrespondenceEstimation<keyPointTYPE,keyPointTYPE> corrEst;
corrEst.setInputSource( source_cloud_FEATures );
corrEst.setInputTarget( target_cloud_FEATures );
corrEst.determineCorrespondences( *corrAll );
// KeyPoint Rejection
pcl::registration::CorrespondenceRejectorSampleConsensus<pcl::PointXYZRGBNormal> corrRej;
corrRej.setInputSource( source_cloud_KEYpt_P_ );
corrRej.setInputTarget( target_cloud_KEYpt_P_ );
corrRej.setInlierThreshold( PARAM_CORR_REJ_InlierThreshold );
corrRej.setMaximumIterations( 10000 );
corrRej.setRefineModel( true );
corrRej.setInputCorrespondences( corrAll );
corrRej.getCorrespondences( *corrFilt );
lum.setCorrespondences( sourceID, targetID, corrFilt );
} // if
} // jjj
} // iii
lum.compute();
// PCLVisualizer - show this - lum.getConcatenatedCloud()
After many days of experimenting with LUM, I decided to move to another tool for Graph optimization, namely g2o. You can see the result in the image, it's not perfect (see small translational drift # frontal view), but it's reasonable and much better than simple pairwise incremental registration (no very-apparent rotational drift!),
If you are interested, I propose downloading the github version! It's the most up-to-date, while other versions - like this - are outdated, and personally I had some compilation issues, both when compiling the library itself or my source code)
Related
I have an issue where a Segfault occurs in random locations but those locations seem to always be the same. The issue also is made more confusing by the fact that the location of the Segfault can change depending on whether I'm using gdb or valgrind to try and solve the issue. This would seem to be a race condition problem but I don't always see any of my destructors being called so I'm not sure why that would be happening. I have not defined my copy constructors which I suppose could be the problem but I would like to understand why that may be.
The tests that I have on the midLevel class to exercise its functionality don't have this problem. Is there something flawed with my basic construction?
My use case is:
In highest level class:
returnObject highLevelClass::performTask( ){
std::shared_ptr< midLevelClass > midClass;
std::vector< someType > dataForClass;
for ( auto it = _someIterate.begin( ); it != _someIterate.end( ); it++ ){
...
buildMidClass( midClass, &dataForClass );
}
...
return returnObject;
}
returnObject highLevelClass::buildMidClass( std::shared_ptr< midLevelClass > &midClass,
std::vector< someType > *dataForClass ){
...
midClass = midLevelClass( _configurationInfo ).create( )
midClass.loadData( dataForClass );
midClass->processData( ); //SOMETIMES IT SEGFAULTS HERE DURING std::vector ALLOCATIONS
...
return returnObject;
}
highLevelClass::~highLevelClass( ){
//SOMETIMES IT SEGFAULTS HERE
return;
}
In the mid-level class:
midLevelClass::loadData( std::vector< someType > *data ){
_data = data; //_data is a std::vector< someType >*
}
std::shared_ptr< midLevelClass > midLevelClass::create( configurationType &_configInfo ){
if ( _configInfo[ "type" ] == childMidLevelClass ){
return std::make_shared< childMidLevelClass >( _configInfo );
}
_error = new errorNode( "create", "The type is not defined" );
return std::make_shared< volumeReconstructionBase >( _config, _error );
}
The answer turned out to be that another std::vector ( that wasn't being accessed by any other part of the code ) was overflowing through a bad access using []. Nothing in gdb or valgrind showed that this was the problem. The answer is probably be careful about using [] to access a std::vector and consider using std::vector::at( ).
I'm writing to the general journal in x++. I am able to post there currently but the dimensions on the line item are not showing up. The code runs just will have 701100- - - - - and the rest not populated on the line item. i'm not sure why... I've tried several different things... such as below.
ledgerDimensions = ["701100","701100", "MIDWHS", "ACCT", "000001", "AIR", "019-000100"];
journalTrans.parmLedgerDimension(AxdDimensionUtil::getLedgerAccountId(ledgerDimensions));
offsetDimensions = ["701100","701100", "MIDWHS", "ACCT", "000001", "AIR", "019-000100"];
journalTrans.parmOffsetLedgerDimension(AxdDimensionUtil::getLedgerAccountId(offsetDimensions));
journaltrans.save()
and also have tried
// dimensionAttribute = DimensionAttribute::findByName("Location");
// dimensionAttributeValue = //DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute, "MINOT");
// dimStorage = DimensionAttributeValueSetStorage::find(0);
// dimStorage.addItem(dimensionAttributeValue);
// journalTrans.parmOffsetDefaultDimension(dimStorage.save());
//journalTrans.save()
both are just adding the account number and nothing else.. don't know why!
I used the service for our import interface for general journal.
Below my code, try it this way, it's easy to create the dimensions with this service.
I copied the code from our system and commented it, if you need any further explaination, ask me.
Declarations:
LedgerGeneralJournal ledgerGeneralJournal;
LedgerGeneralJournalService ledgerGeneralJournalService;
AfStronglyTypedDataContainerList journalHeaderCollection;
LedgerGeneralJournal_LedgerJournalTable journalHeader;
AfStronglyTypedDataContainerList journalLineCollection;
AifEntityKeyList journalHeaderCollectionKeyList;
int journalLineCounter; // to create more than one line
int entityKeyCount;
int journalHeaderCounter; // to create more than one journal header if needed
Add parm methods for your counter variables if needed:
public int parmJournalLineCounter(int _journalLineCounter = journalLineCounter)
{
journalLineCounter = _journalLineCounter;
return journalLineCounter;
}
public int parmJournalHeaderCounter(int _journalHeaderCounter = journalHeaderCounter)
{
journalHeaderCounter = _journalHeaderCounter;
return journalHeaderCounter;
}
initializations:
Header
ledgerGeneralJournalService = LedgerGeneralJournalService::construct();
ledgerGeneralJournal = new LedgerGeneralJournal();
journalHeaderCollection = ledgerGeneralJournal.createLedgerJournalTable();
this.parmJournalLineCounter(0); // note to add a parm method for your counter variables
this.parmJournalHeaderCounter(_newInstance ? 1 : this.parmJournalHeaderCounter() + 1); // i added a parameter if more headers are needed
journalHeader = journalHeaderCollection.insertNew(this.parmJournalHeaderCounter());
journalHeader.parmJournalName(contract.parmJournalNameId()); // init your own journal ID
Here my method to create the lines with dimensions.
Note that i only use CostCenter here, if you need more, add them as done with CostCenter (i commented the lines)
protected void writeLine(
str _oldCompany,
TransDate _transDate,
Voucher _voucher,
str _mainAccountNum,
AmountMST _amount,
LedgerJournalTransTxt _transTxt,
CurrencyCode _currencyCode,
str _offsetAccountNum,
str costCenter
)
{
LedgerGeneralJournal_LedgerJournalTrans journalLine;
AifMultiTypeAccount journalLineLedgerDimensionMain;
AifDimensionAttributeValue journalLineDim1Main;
AfStronglyTypedDataContainerList journalLineDimensionCollectionMain;
AifMultiTypeAccount journalLineLedgerDimensionOffset;
str lineMainAccount;
str lineFullAccount;
str lineMainDimensionName = 'CostCenter';
str lineMainDimensionValue;
str lineOffsetAccount;
str lineOffsetFullAccount;
this.parmJournalLineCounter(this.parmJournalLineCounter()+1);
journalLine = this.parmJournalLineCollection().insertNew(this.parmJournalLineCounter());
journalLine.parmLineNum(this.parmJournalLineCounter());
journalLine.parmCompany(CompanyInfo::findByPTROldCompany(_oldCompany).company());
journalLine.parmOffsetCompany(journalLine.parmCompany());
journalLine.parmTransDate(_transDate);
journalLine.parmVoucher(_voucher);
journalLine.parmAccountType(LedgerJournalACType::Ledger);
lineMainAccount = _mainAccountNum;
journalLine.parmAmountCurCredit(_amount > 0 ? 0 : _amount);
journalLine.parmAmountCurDebit(_amount > 0 ? _amount : 0);
journalLine.parmTxt(_transTxt);
journalLine.parmCurrencyCode(_currencyCode);
journalLine.parmOffsetAccountType(LedgerJournalACType::Ledger);
lineOffsetAccount = _offsetAccountNum;
// Create Main Account Dimensions
journalLineLedgerDimensionMain = journalLine.createLedgerDimension();
journalLineLedgerDimensionMain.parmAccount(lineMainAccount);
lineFullAccount = strFmt("%1-%2-", lineMainAccount, costCenter ? lineMainDimensionValue : ''); // if you need more dimensions, add them here first
journalLineLedgerDimensionMain.parmDisplayValue(lineFullAccount);
// and then add the values here like costcenter:
if (costCenter)
{
lineMainDimensionValue = costCenter;
journalLineDimensionCollectionMain = journalLineLedgerDimensionMain.createValues();
journalLineDim1Main = new AifDimensionAttributeValue();
journalLineDim1Main.parmName(lineMainDimensionName);
journalLineDim1Main.parmValue(lineMainDimensionValue);
journalLineDimensionCollectionMain.add(journalLineDim1Main);
journalLineLedgerDimensionMain.parmValues(journalLineDimensionCollectionMain);
}
journalLine.parmLedgerDimension(journalLineLedgerDimensionMain);
// Create Offset Account Dimensions
// same procedure with offset dimensions if needed
if (_offsetAccountNum)
{
journalLineLedgerDimensionOffset = journalLine.createOffsetLedgerDimension();
journalLineLedgerDimensionOffset.parmAccount(lineOffsetAccount);
lineOffsetFullAccount = strFmt("%1--", lineOffsetAccount);
journalLineLedgerDimensionOffset.parmDisplayValue(lineOffsetFullAccount);
journalLine.parmOffsetLedgerDimension(journalLineLedgerDimensionOffset);
}
}
// Create Lines
journalLineCollection = journalHeader.createLedgerJournalTrans();
Finally to write the journal:
public void finalizeLedgerJournal()
{
int keyCount;
List journalIdList;
journalHeader.parmLedgerJournalTrans(journalLineCollection);
ledgerGeneralJournal.parmLedgerJournalTable(journalHeaderCollection);
journalHeaderCollectionKeyList = LedgerGeneralJournalService.create(ledgerGeneralJournal);
// if you need the journalId for further processing:
this.parmEntityKeyCount(journalHeaderCollectionKeyList.getEntityKeyCount());
if (entityKeyCount > 0)
{
for (keyCount = 1;keyCount <= entityKeyCount;keyCount++)
{
if (!contract.parmJournalIdList())
{
contract.parmJournalIdList(new List(Types::String));
}
journalIdList = contract.parmJournalIdList();
journalIdList.addEnd(LedgerJournalTable::findByRecId(journalHeaderCollectionKeyList.getEntityKey(keyCount).parmRecId()).JournalNum);
contract.parmJournalId(LedgerJournalTable::findByRecId(journalHeaderCollectionKeyList.getEntityKey(keyCount).parmRecId()).JournalNum);
}
}
}
I need help designing the logic of an app that I am working on.
The application should enable users to create mindmaps and save them to a mysql database for later editing.
Each mindmap is made up of inter-related nodes, meaning a node should have a parent node and the id of the mindmap to which it belongs.
I am stuck here. How can I save the nodes to the database and be able to query and rebuild the mindmap tree from the query results.
Root
Child1
Child2
GrandChild1
GreatGrandChild1
GreatGrandChild1
Child3
GrandChild2
I need an algorithm, that can save the nodes and also be able to figure out the relationships/order of items similar to the Tree that I have given. This is very much like how menus are saved and retrieved in Wordpress but I can't find the right logic to do this.
I know there are really great people here. Please help.
This is very easy in a 3 column table.
Column-1: id, Column-2: name, Column-3: parent_id
for example, the data would be like this:
1 ROOT NULL
2 Child1 1
3 Child2 1
... and so on..
I finally found a solution. Here's my full code.
require_once('config.php');//db conn
$connect = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_NAME);
$nav_query = MYSQL_QUERY("SELECT * FROM `nodes` ORDER BY `id`");
$tree = ""; // Clear the directory tree
$depth = 1; // Child level depth.
$top_level_on = 1; // What top-level category are we on?
$exclude = ARRAY(); // Define the exclusion array
ARRAY_PUSH($exclude, 0); // Put a starting value in it
WHILE ( $nav_row = MYSQL_FETCH_ARRAY($nav_query) )
{
$goOn = 1; // Resets variable to allow us to continue building out the tree.
FOR($x = 0; $x < COUNT($exclude); $x++ ) // Check to see if the new item has been used
{
IF ( $exclude[$x] == $nav_row['id'] )
{
$goOn = 0;
BREAK; // Stop looking b/c we already found that it's in the exclusion list and we can't continue to process this node
}
}
IF ( $goOn == 1 )
{
$tree .= $nav_row['name'] . "<br>"; // Process the main tree node
ARRAY_PUSH($exclude, $nav_row['id']); // Add to the exclusion list
IF ( $nav_row['id'] < 6 )
{ $top_level_on = $nav_row['id']; }
$tree .= build_child($nav_row['id']); // Start the recursive function of building the child tree
}
}
FUNCTION build_child($oldID) // Recursive function to get all of the children...unlimited depth
{
$tempTree='<ul>';
GLOBAL $exclude, $depth; // Refer to the global array defined at the top of this script
$child_query = MYSQL_QUERY("SELECT * FROM `nodes` WHERE parent_id=" . $oldID);
WHILE ( $child = MYSQL_FETCH_ARRAY($child_query) )
{
IF ( $child['id'] != $child['parent_id'] )
{
FOR ( $c=0;$c<$depth;$c++ ) // Indent over so that there is distinction between levels
{ $tempTree .= " "; }
$tempTree .= "<li>" . $child['name'] . "</li>";
$depth++; // Incriment depth b/c we're building this child's child tree (complicated yet???)
$tempTree .= build_child($child['id']); // Add to the temporary local tree
$depth--; // Decrement depth b/c we're done building the child's child tree.
ARRAY_PUSH($exclude, $child['id']); // Add the item to the exclusion list
}
}
RETURN $tempTree.'</ul>'; // Return the entire child tree
}
ECHO $tree;
?>
This is based on the piece of code found here http://psoug.org/snippet/PHP-Recursive-function-to-generate-a-parentchild-tree_338.html I hope this helps someone as well
Searched for quite a while now, but I'm stuck at the following problem.
I am using PHPexcel 1.8.0
The spreadsheet is read using the following code:
$rowData = $sheet->rangeToArray('A' . $row . ':' . $highestColumn . $row, NULL, TRUE, TRUE);
So far ok and it works well.
But some spreadsheets contain external referenced data.
And for that I want to use "getOldCalculatedValue".
How do I combine "getOldCalculatedValue" with "rangeToArray" ?
Or is "rangeToArray" inappropriate for this ?
Thanks for any help or hints !
Simple answer, you can't combine the two
rangeToArray() is a simple method for a simple purpose, it doesn't try to do anything clever, simply to return the data from the worksheet as efficiently and quickly as possible
getOldCalculatedValue() is used for a very specific circumstance, and isn't guaranteed to be correct even then, because it retrieves the last value calculated for the cell in MS EXcel itself, which ,ay not be correct if the external workbook wasn't available to MS Excel in that circumstance, or MS Excel formula evaluation was disable.
When calculating cells values from a formula, the PHPExcel calculation engine should use the getOldCalculatedValue() as a fallback if it finds an external reference, and rangeToArray() will try to use this method, but it isn't perfect, especially when that reference in nested deep inside other formulae referenced in other cells.
If you know that a formula in a cell contains an external reference, you should use getOldCalculatedValue() directly for that cell
I came up with the following solution.
Maybe not perfect, but it currently does the job. Thanks for any improvements!
With PHPExcel included and the excel file uploaded and ready, I continue with:
$sheet = $objPHPExcel->getSheet(0);
$highestRow = $sheet->getHighestRow();
Create a new array to store the cell values of a row
$arr_row = array();
Loop through the rows
for ($rownumber = 2; $rownumber <= $highestRow; $rownumber++){
$row = $sheet->getRowIterator($rownumber)->current();
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
Then loop through the cells of the current row
foreach ($cellIterator as $cell) {
Find cells with a formula
$cellcheck = substr($cell->getValue(),0,1);
if($cellcheck == '='){
$cell_content = $cell->getOldCalculatedValue();
}
else{
$cell_content = $cell->getValue();
}
Add the cell values to the array
array_push($arr_row,$cell_content);
Close cell loop
}
At this point I use the $arr_row to do further calculations and string formatting, before finally inserting it into a mysql table.
Close row loop
}
I made some changes in the function rangeToArray() inside Worksheet.php.
Worked fine!
public function rangeToArray($pRange = 'A1', $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) {
// Returnvalue
$returnValue = array();
// Identify the range that we need to extract from the worksheet
list($rangeStart, $rangeEnd) = PHPExcel_Cell::rangeBoundaries($pRange);
$minCol = PHPExcel_Cell::stringFromColumnIndex($rangeStart[0] -1);
$minRow = $rangeStart[1];
$maxCol = PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0] -1);
$maxRow = $rangeEnd[1];
$maxCol++;
// Loop through rows
$r = -1;
for ($row = $minRow; $row <= $maxRow; ++$row) {
$rRef = ($returnCellRef) ? $row : ++$r;
$c = -1;
// Loop through columns in the current row
for ($col = $minCol; $col != $maxCol; ++$col) {
$cRef = ($returnCellRef) ? $col : ++$c;
// Using getCell() will create a new cell if it doesn't already exist. We don't want that to happen
// so we test and retrieve directly against _cellCollection
if ($this->_cellCollection->isDataSet($col.$row)) {
// Cell exists
$cell = $this->_cellCollection->getCacheData($col.$row);
if ($cell->getValue() !== null) {
if ($cell->getValue() instanceof PHPExcel_RichText) {
$returnValue[$rRef][$cRef] = $cell->getValue()->getPlainText();
} else {
if ($calculateFormulas)
{ ##################################### CHANGED LINES
if(!preg_match('/^[=].*/', $cell->getValue()))
{
$returnValue[$rRef][$cRef] = $cell->getCalculatedValue(); # THE ORIGINAL CODE ONLY HAD THIS LINE
}
else
{
$returnValue[$rRef][$cRef] = $cell->getOldCalculatedValue();
}
} ##################################### CHANGED LINES
else
{
$returnValue[$rRef][$cRef] = $cell->getValue();
}
}
if ($formatData) {
$style = $this->_parent->getCellXfByIndex($cell->getXfIndex());
$returnValue[$rRef][$cRef] = PHPExcel_Style_NumberFormat::toFormattedString(
$returnValue[$rRef][$cRef],
($style && $style->getNumberFormat()) ?
$style->getNumberFormat()->getFormatCode() :
PHPExcel_Style_NumberFormat::FORMAT_GENERAL
);
}
} else {
// Cell holds a NULL
$returnValue[$rRef][$cRef] = $nullValue;
}
} else {
// Cell doesn't exist
$returnValue[$rRef][$cRef] = $nullValue;
}
}
}
// Return
return $returnValue;
}
Using shader reflection in Directx 11 you can get information about individual variables by calling
myVar = myCbuffer->GetVariableByName/Index
But if the variable is a struct object, how to get info about the individual struct members?
Note that I'm not talking about the effects framework but pure hlsl and the reflection API.
Variable's member number is stored in it's type description. Use it for iterating it's members using GetMemberTypeByIndex.
Example:
ID3D11ShaderReflectionConstantBuffer* cb = reflector->GetConstantBufferByIndex( cbIndex );
if ( cb )
{
D3D11_SHADER_BUFFER_DESC cbDesc;
cb->GetDesc( &cbDesc );
if ( cbDesc.Type == D3D11_CT_CBUFFER )
{
for ( unsigned i = 0; i < cbDesc.Variables; ++i )
{
ID3D11ShaderReflectionVariable* var = cb->GetVariableByIndex( i );
D3D11_SHADER_VARIABLE_DESC varDesc;
var->GetDesc( &varDesc );
ID3D11ShaderReflectionType* type = var->GetType();
D3D11_SHADER_TYPE_DESC typeDesc;
type->GetDesc( &typeDesc );
for ( unsigned j = 0; j < typeDesc.Members; ++j )
{
ID3D11ShaderReflectionType* memberType = type->GetMemberTypeByIndex( j );
D3D11_SHADER_TYPE_DESC memberTypeDesc;
memberType->GetDesc( &memberTypeDesc );
}
}
}
}
Use GetMemberByName ("If the effect variable is an structure, use this method to look up a member by name."). If the struct has a member "foo", then...
myCbuffer->GetVariableByName->GetMemberByName("foo")
You could use
ID3D11ShaderReflectionType::GetMemberTypeName
This function will returns the field member name of struct in a CBuffer.
I meet the same question when developing my HLSL reflection program. This function has been tried by myself and get correct result.