function featureVector = make3DFeatureVector(depthValidMask, points, scales) % depthValidMask --- binary image which tells depths at which points are % valid. % points = (x,y,X,Y,Z) ---- output from Bubmblee. % scales = unused % This code is copyrighted by Stanford University. % Author: Ashutosh Saxena, Justin Drieymeyer % Code cannot be used for commercial purposes. % Use of the code, if used with permission from authors, must acknowledge: % Learning to Grasp Novel Objects using Vision, % Ashutosh Saxena, Justin Driemeyer, Justin Kearns, Chioma Osondu, Andrew Y. Ng. In 10th International Symposium on Experimental Robotics, ISER, 2006. % Robotic Grasping of Novel Obects, % Ashutosh Saxena, Justing Driemeyer, Justin Kearns, Andrew Y. Ng, In Neural Information Processing Systems (NIPS), 2006. % More details at: http://ai.stanford.edu/~asaxena/learninggrasp/ % Version 0.1: Aug 2006. global columnWidth nGridCol nGridRow rowWidth nGCol = nGridCol; nGRow = nGridRow; pointsBox = [-2, -2, -2; -2, -2, 0; -2, -2, 2; -2, 0, -2; -2, 0, 0; -2, 0, 2; -2, 2, -2; -2, 2, 0; -2, 2, 2; 0, -2, -2; 0, -2, 0; 0, -2, 2; 0, 0, -2; 0, 0, 0; 0, 0, 2; 0, 2, -2; 0, 2, 0; 0, 2, 2; 2, -2, -2; 2, -2, 0; 2, -2, 2; 2, 0, -2; 2, 0, 0; 2, 0, 2; 2, 2, -2; 2, 2, 0; 2, 2, 2]; %pointsBox = [0, 0, 0; -2, 0, 0; 2, 0, 0; 0, -2, 0; 0, 2, 0; 0, 0, -2; 0, 0, 2]; pointsBox = [0, 0, 0; -2, 0, 0; 2, 0, 0; 0, -2, 0; 0, 2, 0; 0, 0, -2; 0, 0, 2; -2, -2, 0; -2, 2, 0; 2, -2, 0; 2, 2, 0; -2, 0, -2; -2, 0, 2; 2, 0, -2; 2, 0, 2; 0, -2, -2; 0, 2, -2; 0, -2, 2; 0, 2, 2;]; basePCACubeTopCorners = [-3, -3, -3; -3, -3, -1; -3, -3, 1; -3, -1, -3; -3, -1, -1; -3, -1, 1; -3, 1, -3; -3, 1, -1; -3, 1, 1; -1, -3, -3; -1, -3, -1; -1, -3, 1; -1, -1, -3; -1, -1, -1; -1, -1, 1; -1, 1, -3; -1, 1, -1; -1, 1, 1; 1, -3, -3; 1, -3, -1; 1, -3, 1; 1, -1, -3; 1, -1, -1; 1, -1, 1; 1, 1, -3; 1, 1, -1; 1, 1, 1]; basePCACubeBotCorners = basePCACubeTopCorners + 2; basePCACubeTopCorners = basePCACubeTopCorners * 1/3; basePCACubeBotCorners = basePCACubeBotCorners * 1/3; neighborGridSize = 10; pointsGrid = zeros(size(depthValidMask, 1), size(depthValidMask, 2), 3); for pointsRow = 1:size(points, 1) pointsGrid(points(pointsRow, 1), points(pointsRow, 2), :) = reshape(points(pointsRow, 3:5), [1, 1, 3]); end reductionFactor = 3; validMask = zeros(size(depthValidMask)); numActiveRows = ceil(size(validMask, 1) / reductionFactor); numActiveCols = ceil(size(validMask, 2) / reductionFactor); rowStep = (size(validMask, 1) - 1) / numActiveRows; colStep = (size(validMask, 2) - 1) / numActiveCols; pickedRows = round(1:rowStep:size(validMask, 1)); pickedCols = round(1:colStep:size(validMask, 2)); validMask(pickedRows, pickedCols) = 1; validMask = validMask & (depthValidMask); %pointsGrid2 = cat(3, repmat((1:size(validMask, 2)), [size(validMask, 1), 1]), pointsGrid); %pointsGrid2 = cat(3, repmat((1:size(validMask, 1))', [1, size(validMask, 2)]), pointsGrid2); %points = reshape(pointsGrid2, [size(pointsGrid2, 1) * size(pointsGrid2, 2), size(pointsGrid2, 3)]); %validVec = reshape(validMask, [size(validMask, 1) * size(validMask, 2), 1]); %points = points(find(validVec), :); pointsGrid = cat(3, (depthValidMask), pointsGrid); totalFeatureVectorOverlay = zeros(size(depthValidMask, 1), size(depthValidMask, 2), 0); numMomentFeats = 16; numPCAMomentFeats = 16; numPercentageFeats = size(pointsBox, 1) * 3; numPCAPercentFeats = size(basePCACubeTopCorners, 1); featStartPercentage = numMomentFeats + numPCAMomentFeats + 1; featStartPCAPercent = featStartPercentage + numPercentageFeats; totalNumFeatPerRad = featStartPCAPercent + numPCAPercentFeats - 1; radVec = [0.025, 0.05]; for rad = radVec radSquared = rad * rad; PCACubeTopCorners = basePCACubeTopCorners * rad; PCACubeBotCorners = basePCACubeBotCorners * rad; thisPointsBox = rad * pointsBox; featureVectorOverlay = zeros(size(depthValidMask, 1), size(depthValidMask, 2), totalNumFeatPerRad); for pointsRow = 1:size(points, 1); if validMask(points(pointsRow, 1), points(pointsRow, 2)) %[points(pointsRow, 1) points(pointsRow, 2)] % select reasonable number of points from 2-d image goodRows = max(1, points(pointsRow, 1)-neighborGridSize):min(size(depthValidMask, 1), points(pointsRow, 1)+neighborGridSize); goodCols = max(1, points(pointsRow, 2)-neighborGridSize):min(size(depthValidMask, 2), points(pointsRow, 2)+neighborGridSize); interestingPoints = reshape(pointsGrid(goodRows, goodCols, :), [length(goodRows) * length(goodCols), size(pointsGrid, 3)]); % now use validity bit to remove invalid points and trim to just xyz coords interestingPoints = interestingPoints(find(interestingPoints(:, 1)), 2:4); moreInterestingPoints = interestingPoints; distToThisPoint = zeros(size(interestingPoints)); distToThisPoint(:, 1) = interestingPoints(:, 1) - points(pointsRow, 3); distToThisPoint(:, 2) = interestingPoints(:, 2) - points(pointsRow, 4); distToThisPoint(:, 3) = interestingPoints(:, 3) - points(pointsRow, 5); %distToThisPoint = interestingPoints - repmat(points(pointsRow, 3:5), [size(interestingPoints, 1), 1]); distToThisPointSquared = (distToThisPoint .* distToThisPoint) * ones(3, 1); neighborRows = find(distToThisPointSquared <= radSquared); neighboringDistances = distToThisPoint(neighborRows, :); neighboringPoints = interestingPoints(neighborRows, :); numOfPoints = size(neighboringPoints, 1); cubeNeighborRows = find((distToThisPoint(:, 1) <= rad) & ... (distToThisPoint(:, 2) <= rad) & ... (distToThisPoint(:, 3) <= rad)); cubeNeighborDist = distToThisPoint(cubeNeighborRows, :); cubeNeighborPoints = interestingPoints(cubeNeighborRows, :); cubeNumOfPoints = size(cubeNeighborDist, 1); [U, S, V] = svd(cubeNeighborDist); newCubeNeighborDist = cubeNeighborDist * V; thisR = points(pointsRow, 1); thisC = points(pointsRow, 2); % Moment Feature 1 & 2 totalDistInXYZ = ones(1, size(neighboringPoints, 1)) * abs(neighboringDistances); totalDivisor = (totalDistInXYZ * ones(3, 1)); if totalDivisor == 0 totalDivisor = 1; end varInXYZ = totalDistInXYZ / numOfPoints; percentageXYZ = totalDistInXYZ / totalDivisor; totalDistInXYZSq = ones(1, size(neighboringPoints, 1)) * (neighboringDistances .* neighboringDistances); totalDivisorSq = (totalDistInXYZSq * ones(3, 1)); if totalDivisorSq == 0 totalDivisorSq = 1; end varInXYZSq = totalDistInXYZSq / numOfPoints; percentageXYZSq = totalDistInXYZSq / totalDivisorSq; featureVectorOverlay(thisR, thisC, 1) = varInXYZ(1); featureVectorOverlay(thisR, thisC, 2) = varInXYZ(2); featureVectorOverlay(thisR, thisC, 3) = varInXYZ(3); featureVectorOverlay(thisR, thisC, 4) = max(varInXYZ); featureVectorOverlay(thisR, thisC, 5) = min(varInXYZ); featureVectorOverlay(thisR, thisC, 6) = varInXYZ * ones(3, 1); featureVectorOverlay(thisR, thisC, 7) = max(percentageXYZ); featureVectorOverlay(thisR, thisC, 8) = min(percentageXYZ); featureVectorOverlay(thisR, thisC, 9) = varInXYZSq(1); featureVectorOverlay(thisR, thisC, 10) = varInXYZSq(2); featureVectorOverlay(thisR, thisC, 11) = varInXYZSq(3); featureVectorOverlay(thisR, thisC, 12) = max(varInXYZSq); featureVectorOverlay(thisR, thisC, 13) = min(varInXYZSq); featureVectorOverlay(thisR, thisC, 14) = varInXYZSq * ones(3, 1); featureVectorOverlay(thisR, thisC, 15) = max(percentageXYZSq); featureVectorOverlay(thisR, thisC, 16) = min(percentageXYZSq); % PCA Moment Feature 1 & 2 totalDistInXYZ = ones(1, size(newCubeNeighborDist, 1)) * abs(newCubeNeighborDist); totalDivisor = (totalDistInXYZ * ones(3, 1)); if totalDivisor == 0 totalDivisor = 1; end varInXYZ = totalDistInXYZ / cubeNumOfPoints; percentageXYZ = totalDistInXYZ / totalDivisor; totalDistInXYZSq = ones(1, size(newCubeNeighborDist, 1)) * (newCubeNeighborDist .* newCubeNeighborDist); totalDivisorSq = (totalDistInXYZSq * ones(3, 1)); if totalDivisorSq == 0 totalDivisorSq = 1; end varInXYZSq = totalDistInXYZSq / cubeNumOfPoints; percentageXYZSq = totalDistInXYZSq / totalDivisorSq; featureVectorOverlay(thisR, thisC, 17) = varInXYZ(1); featureVectorOverlay(thisR, thisC, 18) = varInXYZ(2); featureVectorOverlay(thisR, thisC, 19) = varInXYZ(3); featureVectorOverlay(thisR, thisC, 20) = max(varInXYZ); featureVectorOverlay(thisR, thisC, 21) = min(varInXYZ); featureVectorOverlay(thisR, thisC, 22) = varInXYZ * ones(3, 1); featureVectorOverlay(thisR, thisC, 23) = max(percentageXYZ); featureVectorOverlay(thisR, thisC, 24) = min(percentageXYZ); featureVectorOverlay(thisR, thisC, 25) = varInXYZSq(1); featureVectorOverlay(thisR, thisC, 26) = varInXYZSq(2); featureVectorOverlay(thisR, thisC, 27) = varInXYZSq(3); featureVectorOverlay(thisR, thisC, 28) = max(varInXYZSq); featureVectorOverlay(thisR, thisC, 29) = min(varInXYZSq); featureVectorOverlay(thisR, thisC, 30) = varInXYZSq * ones(3, 1); featureVectorOverlay(thisR, thisC, 31) = max(percentageXYZSq); featureVectorOverlay(thisR, thisC, 32) = min(percentageXYZSq); numOfPlanes = 3; percentages = zeros(size(thisPointsBox, 1), numOfPlanes); for boxRow = 1:size(thisPointsBox, 1); distToThisPoint = zeros(size(moreInterestingPoints)); distToThisPoint(:, 1) = moreInterestingPoints(:, 1) - thisPointsBox(boxRow, 1); distToThisPoint(:, 2) = moreInterestingPoints(:, 2) - thisPointsBox(boxRow, 2); distToThisPoint(:, 3) = moreInterestingPoints(:, 3) - thisPointsBox(boxRow, 3); %distToThisPoint = moreInterestingPoints - repmat(thisPointsBox(boxRow, :), [size(moreInterestingPoints, 1), 1]); distToThisPointSquared = (distToThisPoint .* distToThisPoint) * ones(3, 1); neighborRows = find(distToThisPointSquared <= radSquared); neighboringDistances = distToThisPoint(neighborRows, :); % neighboringPoints = moreInterestingPoints(neighborRows, :); numOfPoints = size(neighboringDistances, 1); if numOfPoints > 0 XYZPlaneSides = neighboringDistances > 0; % For now, just use the three basic planes - YZ, XZ, and XY percentages(boxRow, 1:3) = ones(1, size(XYZPlaneSides, 1)) * XYZPlaneSides; percentages = percentages / numOfPoints; end end featureVectorOverlay(thisR, thisC, featStartPercentage:(featStartPCAPercent - 1)) = reshape(percentages, [1, 1, numPercentageFeats]); PCAFeatIndexes = featStartPCAPercent:totalNumFeatPerRad; if (cubeNumOfPoints > 0); for boxRow = 1:size(PCACubeTopCorners, 1); topCorner = PCACubeTopCorners(boxRow, :); botCorner = PCACubeBotCorners(boxRow, :); inThisBox = ((newCubeNeighborDist(:, 1) >= topCorner(1, 1)) & ... (newCubeNeighborDist(:, 1) < botCorner(1, 1)) & ... (newCubeNeighborDist(:, 2) >= topCorner(1, 2)) & ... (newCubeNeighborDist(:, 2) < botCorner(1, 2)) & ... (newCubeNeighborDist(:, 3) >= topCorner(1, 3)) & ... (newCubeNeighborDist(:, 3) < botCorner(1, 3))); numPointsInThisBox = sum(inThisBox); featureVectorOverlay(thisR, thisC, PCAFeatIndexes(boxRow)) = numPointsInThisBox / cubeNumOfPoints; end; else featureVectorOverlay(thisR, thisC, PCAFeatIndexes) = zeros([1, 1, size(PCACubeTopCorners, 1)]); end; end end totalFeatureVectorOverlay = cat(3, totalFeatureVectorOverlay, featureVectorOverlay); end % Convert point features to patch features % Assume that the image is correctly oriented. imheight = size(depthValidMask, 1); imwidth = size(depthValidMask, 2); % Step sizes in x and y stepwidth = imwidth/nGridCol; stepheight = imheight/nGridRow; featureVector = zeros( nGRow, nGCol, size(totalFeatureVectorOverlay, 3)); for g = 1:nGRow for c = 1:nGCol gridLeft = round( (g - 1)*stepheight + 1); gridRight = round( g*stepheight ); gridTop = round( (c - 1)*stepwidth + 1); gridBot = round( c*stepwidth ); numPoints = sum( sum( validMask(gridLeft:gridRight, gridTop:gridBot))); if numPoints > 0 % totalFeatureVectorOverlay(gridLeft:gridRight, gridTop:gridBot, :) % numPoints % sum( sum( totalFeatureVectorOverlay(gridLeft:gridRight, gridTop:gridBot, :), 2), 1) featureVector(g,c,:) = sum( sum( totalFeatureVectorOverlay(gridLeft:gridRight, gridTop:gridBot, :), 2), 1) / numPoints; end end end return;