Compare commits

..

2 Commits

Author SHA1 Message Date
马学浜 xuebang_ma
617b339d0e Merge branch 'develop' of https://www-map.u533760.nyat.app:55040/windowsSoft/PBAnaly into develop 2025-01-07 18:04:16 +08:00
马学浜 xuebang_ma
a51a1284f2 修改泳道接口,添加多个操作函数 2025-01-07 18:02:26 +08:00
2 changed files with 321 additions and 90 deletions

View File

@ -16,47 +16,53 @@ public:
~PBLane();
private:
//泳道过滤处理函数
//根据输入所有类似泳道的中心X轴坐标groupsX以及泳道的最小最大距离minDifference/maxDifference过滤掉不合规的泳道
std::vector<int> processArray(std::vector<int>& groupsX, int minDifference, int maxDifference);
//宽度/*流*/计算函数,用来计算检测泳道宽度流
vector<int> get_bar_num(vector<unsigned char> buf);
//泳道检测补全函数
//根据泳道位置processX和泳道间距离meanW从图像src中检测临近类泳道位置是否符合泳道特性泳道内两条像素的宽度流应类似且存在条带
std::vector<int> checkArray(std::vector<int>& processX, Mat src, int start_y, int end_y, int meanW);
//条带信息计算函数输入8bit数组rbuf以及过滤范围range此范围内仅保留一个分子
vector<std::array<int, 3>> get_top_point(vector<unsigned char> rbuf, int range);
//单个泳道中条带信息计算(条带位置等)
BandInfo get_protein_lane_data(Mat src, Rect lane);
static bool myCompare(const int& a, const int& b);
static bool myCompare2(const std::array<int, 4>& a, const std::array<int, 4>& b);
public:
//函数:获得图像中泳道位置
//src输入图像需是8bit单通道图像
//返回值:泳道矩形位置信息
std::vector<cv::Rect> getProteinRect(Mat src);
// std::vector<cv::Rect> getProteinRect(Mat src);
//获得蛋白泳道位置src是灰度图像CV_8UC1*ProteinRect_width 是蛋白泳道宽度keep_width = 1时输入固定宽度keep_width = 0时,输出计算得到宽度),
//ProteinRect_height_ratio高度比例高度占图像高度百分之几一般输入90
//返回所有蛋白泳道矩形
std::vector<cv::Rect> getProteinRect(Mat src,int* ProteinRect_width,bool keep_width,int ProteinRect_height_ratio);
//添加泳道proteinRect是当前泳道矩形x是新添加泳道的中心x坐标一般就是鼠标点击图形的x坐标,
//src是输入图形CV_16UC1,unadjustbands是未对齐条带信息需要同步修改
void addProteinRect(std::vector<cv::Rect>& proteinRect,int x,Mat src,std::vector<BandInfo>& unadjustbands);
//删除泳道proteinRect是当前泳道矩形idx是删除泳道的下标序号,unadjustbands是未对齐条带信息需要同步修改
void deleteProteinRect(std::vector<cv::Rect>& proteinRect,int idx,std::vector<BandInfo>& unadjustbands);
//计算单个泳道条带信息src是输入图形CV_16UC1lane是泳道对应矩形
//返回BandInfo条带结果
BandInfo get_protein_lane_data(Mat src,Rect lane);
//获得所有泳道未对齐的条带结果src是输入图形CV_16UC1lane是泳道对应矩形
//返回所有泳道未对齐的条带结果
std::vector<BandInfo> getProteinBands(Mat src,std::vector<cv::Rect> lanes);
//修改泳道宽度和高度和已经计算出的未对齐条带信息src是输入图形CV_16UC1proteinRect是当前泳道矩形
//ProteinRect_width是新的蛋白泳道宽度,ProteinRect_height_ratio是新的高度比例高度占图像高度百分之几一般输入90
//unadjustbands是未对齐的所有泳道条带信息
//输入的条带必须是未对齐的调整后数据需要重新对齐和计算分子量调用adjustBands和molecularWeightResult
void modifyProteinRectAndBands(Mat src,std::vector<cv::Rect>& proteinRect,int ProteinRect_width,int ProteinRect_height_ratio,std::vector<BandInfo>& unadjustbands);
//根据鼠标点击图形的坐标,输出当前位置的泳道下标和条带下标
//lanes是泳道信息bands是对应条带信息不关心对齐或者未对齐x、y是坐标lanesIndex是传回鼠标点击位置的泳道下标bandsIndex是鼠标点击位置的条带下标
void getLaneBandsIndex(std::vector<cv::Rect> lanes,std::vector<BandInfo> bands,int x,int y,int* lanesIndex,int* bandsIndex);
//根据鼠标点击图形的坐标添加条带,lanes是泳道信息lanesIndex是鼠标点击位置是第几条泳道unadjustbands是未对齐的所有泳道条带信息原始鼠标点击位置的y坐标
//输入的条带必须是未对齐的调整后数据需要重新对齐和计算分子量调用adjustBands和molecularWeightResult
void addProteinBand(std::vector<cv::Rect> lanes,int lanesIndex,std::vector<BandInfo>& unadjustbands,int y);
//根据鼠标点击图形的坐标删除条带,lanesIndex是鼠标点击位置是第几条泳道unadjustbands是未对齐的所有泳道条带信息bandsIndex是鼠标点击位置是第几个条带
//输入的条带必须是未对齐的调整后数据需要重新对齐和计算分子量调用adjustBands和molecularWeightResult
void deleteProteinBand(int lanesIndex,std::vector<BandInfo>& unadjustbands,int bandsIndex);
//对齐所有泳道的条带结果unadjustbands是所有泳道的条带结果range是条带中心在多少像素范围内属于同一类型条带一般写10
//返回对齐后的所有泳道的条带结果(未计算分子量)
std::vector<BandInfo> adjustBands(std::vector<BandInfo> unadjustbands, int range);
//计算得到分子量结果
void molecularWeightResult(std::vector<cv::Rect> lanes,std::vector<BandInfo>& bands);
////函数:获得图像中泳道对应的条带信息
////src输入图像需是16bit单通道图像
////lanes泳道矩形位置信息
////返回值:对应条带位置信息
std::vector<BandInfo> getProteinBands(Mat src, std::vector<cv::Rect> lanes);
////函数:条带分子匹配排序函数
////bands所有条带位置信息
////rangeY轴差在range范围内的表示和泳道1匹配
////返回值结果修改在bands中
void adjustBands(std::vector<BandInfo>& bands, int range);
////函数:计算所有条带的分子信息
////lanes输入泳道信息
////bands输入条带信息对应输出的分子信息在这个结构体中
void molecularWeightResult(std::vector<cv::Rect> lanes, std::vector<BandInfo>& bands);
};

View File

@ -259,7 +259,7 @@ std::vector<int> PBLane::checkArray(std::vector<int>& processX, Mat src, int sta
return result;
}
vector<std::array<int, 3>> PBLane::get_top_point(vector<unsigned char> rbuf, int range)
vector<std::array<int, 3>> PBLane::get_top_point(vector<unsigned short> rbuf, int range)
{
vector<std::array<int, 2>> point;
vector<char> diff(rbuf.size());
@ -279,7 +279,7 @@ vector<std::array<int, 3>> PBLane::get_top_point(vector<unsigned char> rbuf, int
}
for (int i = rbuf.size() - 1; i >= 0; i--)
{
if (diff[i] == 0 && i == rbuf.size() - 1)
if (i == rbuf.size() - 1 && diff[i] == 0)
{
diff[i] = 1;
}
@ -437,37 +437,12 @@ vector<std::array<int, 3>> PBLane::get_top_point(vector<unsigned char> rbuf, int
return topPoint;
}
BandInfo PBLane::get_protein_lane_data(Mat src, Rect lane)
{
BandInfo band;
int sum = 0;
vector<unsigned char> cdata;
for (int i = lane.y; i < lane.y + lane.height; i++)
{
sum = 0;
for (int j = lane.x; j < lane.x + lane.width; j++)
{
sum += src.at<unsigned short>(i, j);
}
sum /= lane.width;
band.land_data.push_back((unsigned short)sum);
band.ydata.push_back((float)((65535 - sum) / 255.0));
cdata.push_back((unsigned char)((65535 - sum) >> 8));
}
for (int i = 0; i < lane.height; i++)
{
band.xdata.push_back((float)i / lane.height);
}
band.band_point = get_top_point(cdata, 8);
return band;
}
PBLane::PBLane() {}
PBLane::~PBLane() {}
std::vector<cv::Rect> PBLane::getProteinRect(Mat src)
std::vector<cv::Rect> PBLane::getProteinRect(Mat src,int* ProteinRect_width,bool keep_width,int ProteinRect_height_ratio)
{
cv::Mat edges;
Canny(src, edges, 50, 150);
@ -483,7 +458,7 @@ std::vector<cv::Rect> PBLane::getProteinRect(Mat src)
continue;
}
double rotia = 0.0;
rotia = (double)rect.width / rect.height;
rotia = (double)rect.width/rect.height;
if (rotia >= 7 || rotia <= 2) {
continue;
}
@ -495,27 +470,28 @@ std::vector<cv::Rect> PBLane::getProteinRect(Mat src)
std::vector<int> allW(boundingRects.size());
int up = src.rows;
int down = 0;
for (int i = 0; i < boundingRects.size(); i++)
for (int i = 0;i<boundingRects.size();i++)
{
allX[i] = boundingRects[i].x + boundingRects[i].width / 2;
allY[i] = boundingRects[i].y + boundingRects[i].height / 2;
allX[i] = boundingRects[i].x + boundingRects[i].width/2;
allY[i] = boundingRects[i].y + boundingRects[i].height/2;
allW[i] = boundingRects[i].width;
up = min(boundingRects[i].y, up);
down = max(boundingRects[i].y + boundingRects[i].height, down);
up = min(boundingRects[i].y,up);
down = max(boundingRects[i].y + boundingRects[i].height,down);
}
int meanW = 0;
int meanY = 0;
int maxH = 0;
std::sort(allW.begin(), allW.end(), myCompare);
std::sort(allY.begin(), allY.end(), myCompare);
std::sort(allX.begin(), allX.end(), myCompare);
std::sort(allW.begin(), allW.end(), [](const int& a, const int& b) {
return a < b;
});
std::sort(allY.begin(), allY.end(), [](const int& a, const int& b) {
return a < b;
});
std::sort(allX.begin(), allX.end(), [](const int& a, const int& b) {
return a < b;
});
int cnt = 0;
if (boundingRects.size() == 0)
{
std::vector<cv::Rect> proteinRect1(boundingRects.size());
return proteinRect1;
}
for (int i = boundingRects.size() / 3; i <= 2 * boundingRects.size() / 3; i++)
for(int i = boundingRects.size()/3;i <= 2*boundingRects.size()/3;i++)
{
cnt++;
meanW += allW[i];
@ -524,37 +500,99 @@ std::vector<cv::Rect> PBLane::getProteinRect(Mat src)
meanW /= cnt;
meanY /= cnt;
maxH = max(down - meanY, meanY - up) * 2;
maxH = max(maxH, src.rows / 3);
maxH = max(maxH,src.rows/3);
std::vector<int> groupsX;
const int n = 3;
int sumX = allX[0];
cnt = 1;
for (int i = 1; i < boundingRects.size(); i++) {
if (allX[i] - allX[i - 1] > n)
if (allX[i] - allX[i-1] > n)
{
groupsX.push_back(sumX / cnt);
groupsX.push_back(sumX/cnt);
sumX = 0;
cnt = 0;
}
sumX += allX[i];
cnt++;
}
groupsX.push_back(sumX / cnt);
groupsX.push_back(sumX/cnt);
std::vector<int> processX = processArray(groupsX, meanW, meanW * 1.8);
std::vector<int> proteinX = checkArray(processX, src, 15, src.rows - 30, meanW);
std::vector<int> processX = processArray(groupsX,meanW,meanW*1.8);
std::vector<int> proteinX = checkArray(processX, src,15,src.rows - 30,meanW);
std::vector<cv::Rect> proteinRect(proteinX.size());
for (int i = 0; i < proteinX.size(); i++)
for(int i = 0;i<proteinX.size();i++)
{
proteinRect[i].x = proteinX[i] - meanW / 2;
proteinRect[i].y = 15;//meanY - maxH/2;
if(keep_width == 1){
meanW = *ProteinRect_width;
}
else{
*ProteinRect_width = meanW;
}
int y_start = src.rows * (100 - ProteinRect_height_ratio) / 200;
proteinRect[i].x = proteinX[i] - meanW/2;
proteinRect[i].y = y_start;
proteinRect[i].width = meanW;
proteinRect[i].height = src.rows - 30;
proteinRect[i].height = src.rows - y_start * 2;
}
return proteinRect;
}
void PBLane::addProteinRect(std::vector<cv::Rect>& proteinRect,int x,Mat src,std::vector<BandInfo>& unadjustbands)
{
Rect new_proteinRect;
new_proteinRect.x = x - proteinRect[0].width/2;
new_proteinRect.y = proteinRect[0].y;
new_proteinRect.width = proteinRect[0].width;
new_proteinRect.height = proteinRect[0].height;
BandInfo band = get_protein_lane_data(src,new_proteinRect);
for (auto it = proteinRect.begin(); it != proteinRect.end(); ++it) {
if (it->x > new_proteinRect.x) {
size_t index = std::distance(proteinRect.begin(), it);
proteinRect.insert(it, new_proteinRect);
unadjustbands.insert(unadjustbands.begin() + index, band);
return;
}
}
proteinRect.push_back(new_proteinRect);
unadjustbands.push_back(band);
return;
}
void PBLane::deleteProteinRect(std::vector<cv::Rect>& proteinRect,int idx,std::vector<BandInfo>& unadjustbands)
{
if (idx < proteinRect.size()) {
proteinRect.erase(proteinRect.begin() + idx);
unadjustbands.erase(unadjustbands.begin() + idx);
} else {
std::cout << "idx out of range!" << std::endl;
}
return;
}
BandInfo PBLane::get_protein_lane_data(Mat src, Rect lane)
{
BandInfo band;
int sum = 0;
vector<unsigned short> cdata;
for (int i = lane.y; i < lane.y + lane.height; i++)
{
sum = 0;
for (int j = lane.x; j < lane.x + lane.width; j++)
{
sum += src.at<unsigned short>(i, j);
}
sum /= lane.width;
band.land_data.push_back((unsigned short)sum);
band.ydata.push_back((float)((65535 - sum) / 255.0));
cdata.push_back(65535 - sum);
}
for (int i = 0; i < lane.height; i++)
{
band.xdata.push_back((float)i / lane.height);
}
band.band_point = get_top_point(cdata, 8);
return band;
}
std::vector<BandInfo> PBLane::getProteinBands(Mat src, std::vector<cv::Rect> lanes)
{
@ -580,11 +618,198 @@ std::vector<BandInfo> PBLane::getProteinBands(Mat src, std::vector<cv::Rect> lan
return bands;
}
void PBLane::adjustBands(std::vector<BandInfo>& bands, int range)
void PBLane::modifyProteinRectAndBands(Mat src,std::vector<cv::Rect>& proteinRect,int ProteinRect_width,int ProteinRect_height_ratio,std::vector<BandInfo>& unadjustbands)
{
// 用于存储所有的值及其对应的列索引
std::map<int, int> columnMap;
int y_start = src.rows * (100 - ProteinRect_height_ratio) / 200;
int det_y = proteinRect[0].y - y_start;
for(int i = 0;i<proteinRect.size();i++)
{
proteinRect[i].x = proteinRect[i].x - (ProteinRect_width - proteinRect[i].width)/2;
proteinRect[i].y = y_start;
proteinRect[i].width = ProteinRect_width;
proteinRect[i].height = src.rows - y_start * 2;
}
int sum = 0;
for(int n = 0; n < proteinRect.size(); n++)
{
unadjustbands[n].land_data.clear();
unadjustbands[n].ydata.clear();
unadjustbands[n].xdata.clear();
for(int i = proteinRect[n].y; i < proteinRect[n].y + proteinRect[n].height; i++)
{
sum = 0;
for(int j = proteinRect[n].x; j < proteinRect[n].x + proteinRect[n].width; j++)
{
sum+=src.at<unsigned short>(i,j);
}
sum/=proteinRect[n].width;
unadjustbands[n].land_data.push_back((unsigned short)sum);
unadjustbands[n].ydata.push_back((float)((65535 - sum)/255.0));
}
for(int i = 0; i < proteinRect[n].height; i++)
{
unadjustbands[n].xdata.push_back((float)i/proteinRect[n].height);
}
for(int i = 0; i < unadjustbands[n].band_point.size(); i++)
{
//fix left and right
unadjustbands[n].band_point[i][1] += det_y;
unadjustbands[n].band_point[i][2] += det_y;
//fix top
int y1 = unadjustbands[n].band_point[i][1];
int y2 = unadjustbands[n].band_point[i][2];
float temp = unadjustbands[n].ydata[y1];
for(int j = y1 + 1; j < y2; j++)
{
if(unadjustbands[n].ydata[j] > temp){
temp = unadjustbands[n].ydata[j];
unadjustbands[n].band_point[i][0] = j;
}
}
}
}
}
void PBLane::getLaneBandsIndex(std::vector<cv::Rect> lanes,std::vector<BandInfo> bands,int x,int y,int* lanesIndex,int* bandsIndex)
{
*lanesIndex = -1;
*bandsIndex = -1;
int ystart = lanes[0].y;
int yend = lanes[0].y + lanes[0].height - 1;
if(y > yend || y < ystart)
{
return ;
}
for (int i = 0; i < lanes.size(); i++) {
int xstart = lanes[i].x;
int xend = lanes[i].x + lanes[i].width - 1;
if(x <= xend && x >= xstart){
*lanesIndex = i;
break;
}
}
for (int j = 0; j < bands[*lanesIndex].band_point.size(); j++) {
int y1 = bands[*lanesIndex].band_point[j][1] + ystart;
int y2 = bands[*lanesIndex].band_point[j][2] + ystart;
if(y <= y2 && y >= y1){
*bandsIndex = j;
break;
}
}
return;
}
void PBLane::addProteinBand(std::vector<cv::Rect> lanes,int lanesIndex,std::vector<BandInfo>& unadjustbands,int y)
{
int ystart = lanes[lanesIndex].y;
int yend = lanes[lanesIndex].y + lanes[lanesIndex].height - 1;
int y1 = 0;
int y2 = lanes[lanesIndex].height;
if(y < ystart || y > yend)
{
return ;
}
int rect_y = y - lanes[lanesIndex].y;
for(int i = 0; i < unadjustbands[lanesIndex].band_point.size(); i++)
{
y2 = unadjustbands[lanesIndex].band_point[i][1];
if(rect_y >= y1 && rect_y < y2)
{
break;
}
else
{
y1 = unadjustbands[lanesIndex].band_point[i][2];
}
}
if(y1 > y2)
{
y2 = lanes[lanesIndex].height;
}
//fine top
int range = 8;
int top_start = rect_y - range;
int top_end = rect_y + range;
if(top_start < y1){
top_start = y1;
}
if(top_end > y2){
top_end = y2;
}
std::array<int, 3> new_band_point;
new_band_point[0] = top_start;
float temp = unadjustbands[lanesIndex].ydata[top_start];
float mean = unadjustbands[lanesIndex].ydata[top_start];
for(int i = top_start + 1; i < top_end; i++)
{
mean += unadjustbands[lanesIndex].ydata[i];
if(unadjustbands[lanesIndex].ydata[i] > temp){
temp = unadjustbands[lanesIndex].ydata[i];
new_band_point[0] = i;
}
}
mean /= (top_end - top_start);
//fine left
temp = unadjustbands[lanesIndex].ydata[new_band_point[0]];
new_band_point[1] = y1;
for(int i = new_band_point[0] - 1; i > y1; i--)
{
if(unadjustbands[lanesIndex].ydata[i] > temp)
{
if(temp < mean)
{
new_band_point[1] = i+1;
break;
}
}
temp = unadjustbands[lanesIndex].ydata[i];
}
//fine right
temp = unadjustbands[lanesIndex].ydata[new_band_point[0]];
new_band_point[2] = y2;
for(int i = new_band_point[0] + 1; i < y2; i++)
{
if(unadjustbands[lanesIndex].ydata[i] > temp)
{
if(temp < mean)
{
new_band_point[2] = i+1;
break;
}
}
temp = unadjustbands[lanesIndex].ydata[i];
}
for (auto it = unadjustbands[lanesIndex].band_point.begin(); it != unadjustbands[lanesIndex].band_point.end(); ++it) {
if ((*it)[0] > new_band_point[0]) {
unadjustbands[lanesIndex].band_point.insert(it, new_band_point);
return;
}
}
unadjustbands[lanesIndex].band_point.push_back(new_band_point);
return ;
}
void PBLane::deleteProteinBand(int lanesIndex,std::vector<BandInfo>& unadjustbands,int bandsIndex)
{
if (bandsIndex < unadjustbands[lanesIndex].band_point.size()) {
unadjustbands[lanesIndex].band_point.erase(unadjustbands[lanesIndex].band_point.begin() + bandsIndex);
} else {
std::cout << "bandsIndex out of range!" << std::endl;
}
return;
}
std::vector<BandInfo> PBLane::adjustBands(std::vector<BandInfo> unadjustbands, int range)
{
// 用于存储所有的值及其对应的列索引
std::map<int, int> columnMap;
std::vector<BandInfo> bands = unadjustbands;
std::vector<std::array<int, 4>> vec;
for (int i = 0; i < bands.size(); i++)