调整OpenCV Mat矢量大小时的意外结果

时间:2017-12-22 03:58:04

标签: c++ opencv vector

我在Ubuntu 16.04,GCC 5.4,最新的OpenCV。假设我有一个double的向量

import React, { Component } from 'react';
import { View, Text, FlatList, ActivityIndicator, Alert, TouchableOpacity} from "react-native";
import { List, ListItem, Icon } from "react-native-elements";
import { Navigator } from 'react-navigation';
import SearchBar from './SearchBar';


export default class Customer extends Component {

  state = {
    loading: false,
    data: []
  }

  componentWillMount() {
    this.searchCust('M000');
  }

  onPressSearch = term => {
    if(term == '')
      {
        Alert.alert("Enter to search");
      }
    else
    {
      this.searchCust(term);
    }
  }

  searchCust = term => {
    this.setState({ loading: true });

      const url = `http://xxx.xxx.xxx.xxx/app/customerlist.php?term=${term}`;
        fetch(url)
          .then(res => res.json())
          .then(res => {
            this.setState({
              data: res.results,
              error: res.error || null,
              loading: false,
            });
          })
        .catch(error => {
          this.setState({ error });
      });
  }

  goToCustomerDetail = (item) => {
    this.props.navigation.navigate("CustomerDetail",{item});      //Alert.alert(item);//
  }
  render() {
    const { loading, data } = this.state;
    const { customers } = this.props;

    return (
      <View style={{ flex: 1, backgroundColor: '#fff' }}>
        <SearchBar
          loading={loading}
          onPressSearch={this.onPressSearch}
        />

        <List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
          <FlatList
            data={data}
            renderItem={({ item }) => {
              const badge = {
                value: `☆ ${item.custstar}`, {/* d is a database field*/}
                badgeContainerStyle: { right: 10, backgroundColor: '#56579B' },
                badgeTextStyle: { fontSize: 12 },
              };  

              return (
                 <TouchableOpacity onPress={this.goToCustomerDetail.bind(this, item.custid)}>
                  <ListItem
                    style={{backgroundColor: 'transparent'}}
                    roundAvatar
                    title={`${item.custid}`}
                    subtitle={item.custname}
                    avatar={{ uri: item.imageurl }}
                    badge={badge}
                    containerStyle={{ borderBottomWidth: 1 }}

                  />
                 </TouchableOpacity>
              );
            }
            }
            keyExtractor={item => item.custid}
            ItemSeparatorComponent={this.renderSeparator}
            ListHeaderComponent={this.renderHeader}
            ListFooterComponent={this.renderFooter}
            onRefresh={this.handleRefresh}
            refreshing={this.state.refreshing}
            onEndReached={this.handleLoadMore}
            onEndReachedThreshold={0.5}
          />
        </List>
      </View>
    );
  }
}

打印

  std::vector<std::vector<double>> vecvecdouble;

  vecvecdouble.resize(3, std::vector<double>(3, 0));

  for (int j = 0; j < 3; j++){
    for (int i = 0; i < 3; i++){
      if (i == 0){
        vecvecdouble[i][j] = 1;
        vecvecdouble[i][j] = 1;
      }
      if (i == 1){
        vecvecdouble[i][j] = 2;
        vecvecdouble[i][j] = 2;
      }

      if (i == 1 && j == 0){
        std::cout << vecvecdouble[i - 1][j] << std::endl;
        std::cout << vecvecdouble[i][j] << std::endl;
        std::cout << vecvecdouble[i + 1][j] << std::endl;
      }
    }
  }

正如所料。但是,如果我使用OpenCV 1 2 0

做同样的事情
cv::mat

打印

  std::vector<std::vector<cv::Mat>> vecvecmat;

  vecvecmat.resize(
      3, std::vector<cv::Mat>(3, cv::Mat(4, 4, CV_64FC1, cv::Scalar(0.0))));

  for (int j = 0; j < 3; j++){
    for (int i = 0; i < 3; i++){
      if (i == 0){
        vecvecmat[i][j].at<double>(0, 0) = 1;
        vecvecmat[i][j].at<double>(0, 1) = 1;
      }
      if (i == 1){
        vecvecmat[i][j].at<double>(0, 0) = 2;
        vecvecmat[i][j].at<double>(0, 1) = 2;
      }

      if (i == 1 && j == 0){
        std::cout << vecvecmat[i - 1][j] << std::endl;
        std::cout << vecvecmat[i][j] << std::endl;
        std::cout << vecvecmat[i + 1][j] << std::endl;
      }
    }
  }

这完全出乎意料,因为我期待它打印

[2, 2, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]
[2, 2, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]
[2, 2, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]

但是,如果我不尝试在一行中调整向量的大小并经历两个for循环,它实际上会返回预期的结果

[1, 1, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]
[2, 2, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]
[0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]

这条线有什么问题?

  std::vector<std::vector<cv::Mat>> vecvecmat;

  vecvecmat.resize(3);

  for (int i = 0; i < 3; i++){
    for (int j = 0; j < 3; j++){
      cv::Mat mymat = cv::Mat(4, 4, CV_64FC1, cv::Scalar(0.0));

      vecvecmat[i].push_back(mymat);
    }
  }

  for (int j = 0; j < 3; j++){
    for (int i = 0; i < 3; i++){
      if (i == 0){
        vecvecmat[i][j].at<double>(0, 0) = 1;
        vecvecmat[i][j].at<double>(0, 1) = 1;
      }
      if (i == 1){
        vecvecmat[i][j].at<double>(0, 0) = 2;
        vecvecmat[i][j].at<double>(0, 1) = 2;
      }

      if (i == 1 && j == 0){
        std::cout << vecvecmat[i - 1][j] << std::endl;
        std::cout << vecvecmat[i][j] << std::endl;
        std::cout << vecvecmat[i + 1][j] << std::endl;
      }
    }
  }

1 个答案:

答案 0 :(得分:2)

cv::Mat says的复制构造函数的文档(强调我的):

  

参数

     

m将(整体或部分)数组分配给构造的矩阵。 这些构造函数不会复制数据。而是构造指向m数据或其子数组的标头并将其与之关联。参考计数器(如果有)递增。因此,当您修改使用此类构造函数形成的矩阵时,还会修改m 的相应元素。如果您想拥有子阵列的独立副本,请使用Mat::clone()

您在调用std::vector::resize时构造的初始矩阵正在使用此复制构造函数*复制到向量的每个元素中,因此它们都指向相同的数据。修改一个矩阵时,可以修改所有矩阵。

*或者可能与operator=,它做同样的事情(我不确定哪一个,但它不影响结果)

我建议像这样初始化你的矢量:

std::vector<std::vector<cv::Mat>> vecvecmat;
vecvecmat.resize(3, std::vector<cv::Mat>());
for(auto& v : vecvecmat)
{
    for(std::size_t i = 0; i < 3; ++i)
    {
        v.emplace_back(4, 4, CV_64FC1, cv::Scalar(0.0));
    }
}